@pascal-app/core 1.0.0-beta.4 → 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 (263) 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-manager.d.ts +12 -0
  18. package/dist/hooks/spatial-grid/spatial-grid-manager.d.ts.map +1 -1
  19. package/dist/hooks/spatial-grid/spatial-grid-manager.js +39 -1
  20. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts +2785 -1
  21. package/dist/hooks/spatial-grid/spatial-grid-sync.d.ts.map +1 -1
  22. package/dist/hooks/spatial-grid/spatial-grid-sync.js +132 -19
  23. package/dist/hooks/spatial-grid/support-host-patch.d.ts +45 -1
  24. package/dist/hooks/spatial-grid/support-host-patch.d.ts.map +1 -1
  25. package/dist/hooks/spatial-grid/support-host-patch.js +171 -6
  26. package/dist/index.d.ts +15 -6
  27. package/dist/index.d.ts.map +1 -1
  28. package/dist/index.js +17 -5
  29. package/dist/lib/asset-storage.d.ts.map +1 -1
  30. package/dist/lib/asset-storage.js +4 -1
  31. package/dist/lib/polygon-union.d.ts +4 -0
  32. package/dist/lib/polygon-union.d.ts.map +1 -0
  33. package/dist/lib/polygon-union.js +306 -0
  34. package/dist/lib/roof-overlap.d.ts +32 -0
  35. package/dist/lib/roof-overlap.d.ts.map +1 -0
  36. package/dist/lib/roof-overlap.js +72 -0
  37. package/dist/lib/room-topology-index.d.ts +50 -0
  38. package/dist/lib/room-topology-index.d.ts.map +1 -0
  39. package/dist/lib/room-topology-index.js +237 -0
  40. package/dist/lib/slab-polygon.d.ts +35 -2
  41. package/dist/lib/slab-polygon.d.ts.map +1 -1
  42. package/dist/lib/slab-polygon.js +133 -27
  43. package/dist/lib/space-detection.d.ts +40 -3
  44. package/dist/lib/space-detection.d.ts.map +1 -1
  45. package/dist/lib/space-detection.js +890 -246
  46. package/dist/registry/handles.d.ts +24 -3
  47. package/dist/registry/handles.d.ts.map +1 -1
  48. package/dist/registry/index.d.ts +3 -3
  49. package/dist/registry/index.d.ts.map +1 -1
  50. package/dist/registry/index.js +1 -1
  51. package/dist/registry/registry.d.ts +29 -6
  52. package/dist/registry/registry.d.ts.map +1 -1
  53. package/dist/registry/registry.js +111 -4
  54. package/dist/registry/scene-api.d.ts +16 -0
  55. package/dist/registry/scene-api.d.ts.map +1 -1
  56. package/dist/registry/scene-api.js +49 -1
  57. package/dist/registry/types.d.ts +261 -13
  58. package/dist/registry/types.d.ts.map +1 -1
  59. package/dist/registry/use-registry-version.d.ts +11 -0
  60. package/dist/registry/use-registry-version.d.ts.map +1 -0
  61. package/dist/registry/use-registry-version.js +15 -0
  62. package/dist/schema/__bench__/node-parsers.bench.d.ts +24 -0
  63. package/dist/schema/__bench__/node-parsers.bench.d.ts.map +1 -0
  64. package/dist/schema/__bench__/node-parsers.bench.js +314 -0
  65. package/dist/schema/__fixtures__/node-fixtures.d.ts +28 -0
  66. package/dist/schema/__fixtures__/node-fixtures.d.ts.map +1 -0
  67. package/dist/schema/__fixtures__/node-fixtures.js +125 -0
  68. package/dist/schema/base.d.ts +1 -1
  69. package/dist/schema/base.d.ts.map +1 -1
  70. package/dist/schema/base.js +8 -1
  71. package/dist/schema/compiled-node-parsers.d.ts +40 -0
  72. package/dist/schema/compiled-node-parsers.d.ts.map +1 -0
  73. package/dist/schema/compiled-node-parsers.js +95 -0
  74. package/dist/schema/index.d.ts +20 -15
  75. package/dist/schema/index.d.ts.map +1 -1
  76. package/dist/schema/index.js +19 -12
  77. package/dist/schema/material.d.ts +2 -1
  78. package/dist/schema/material.d.ts.map +1 -1
  79. package/dist/schema/material.js +1 -0
  80. package/dist/schema/nodes/automatic-downspout.d.ts +17 -0
  81. package/dist/schema/nodes/automatic-downspout.d.ts.map +1 -0
  82. package/dist/schema/nodes/automatic-downspout.js +237 -0
  83. package/dist/schema/nodes/block.d.ts +107 -0
  84. package/dist/schema/nodes/block.d.ts.map +1 -0
  85. package/dist/schema/nodes/block.js +207 -0
  86. package/dist/schema/nodes/box-vent.d.ts +8 -2
  87. package/dist/schema/nodes/box-vent.d.ts.map +1 -1
  88. package/dist/schema/nodes/box-vent.js +2 -0
  89. package/dist/schema/nodes/building.d.ts +1 -1
  90. package/dist/schema/nodes/cabinet.d.ts +25 -3
  91. package/dist/schema/nodes/cabinet.d.ts.map +1 -1
  92. package/dist/schema/nodes/cabinet.js +26 -5
  93. package/dist/schema/nodes/ceiling.d.ts +1 -1
  94. package/dist/schema/nodes/chimney.d.ts +2 -2
  95. package/dist/schema/nodes/column.d.ts +6 -6
  96. package/dist/schema/nodes/construction-dimension.d.ts +4 -4
  97. package/dist/schema/nodes/cupola.d.ts +9 -1
  98. package/dist/schema/nodes/cupola.d.ts.map +1 -1
  99. package/dist/schema/nodes/cupola.js +2 -0
  100. package/dist/schema/nodes/door.d.ts +1 -1
  101. package/dist/schema/nodes/dormer.d.ts +44 -1
  102. package/dist/schema/nodes/dormer.d.ts.map +1 -1
  103. package/dist/schema/nodes/dormer.js +131 -7
  104. package/dist/schema/nodes/downspout.d.ts +11 -1
  105. package/dist/schema/nodes/downspout.d.ts.map +1 -1
  106. package/dist/schema/nodes/downspout.js +24 -0
  107. package/dist/schema/nodes/duct-fitting.d.ts +18 -1
  108. package/dist/schema/nodes/duct-fitting.d.ts.map +1 -1
  109. package/dist/schema/nodes/duct-fitting.js +25 -4
  110. package/dist/schema/nodes/duct-segment.d.ts +23 -1
  111. package/dist/schema/nodes/duct-segment.d.ts.map +1 -1
  112. package/dist/schema/nodes/duct-segment.js +20 -0
  113. package/dist/schema/nodes/duct-terminal.d.ts +1 -1
  114. package/dist/schema/nodes/elevator.d.ts +1 -1
  115. package/dist/schema/nodes/eyebrow-vent.d.ts +8 -2
  116. package/dist/schema/nodes/eyebrow-vent.d.ts.map +1 -1
  117. package/dist/schema/nodes/eyebrow-vent.js +2 -0
  118. package/dist/schema/nodes/fence.d.ts +1 -1
  119. package/dist/schema/nodes/guide.d.ts +1 -1
  120. package/dist/schema/nodes/gutter.d.ts +36 -2
  121. package/dist/schema/nodes/gutter.d.ts.map +1 -1
  122. package/dist/schema/nodes/gutter.js +308 -1
  123. package/dist/schema/nodes/hanger-overrides.d.ts +7 -0
  124. package/dist/schema/nodes/hanger-overrides.d.ts.map +1 -0
  125. package/dist/schema/nodes/hanger-overrides.js +6 -0
  126. package/dist/schema/nodes/hvac-equipment.d.ts +1 -1
  127. package/dist/schema/nodes/item.d.ts +4 -3
  128. package/dist/schema/nodes/item.d.ts.map +1 -1
  129. package/dist/schema/nodes/item.js +5 -0
  130. package/dist/schema/nodes/lean-to-extension.d.ts +212 -0
  131. package/dist/schema/nodes/lean-to-extension.d.ts.map +1 -0
  132. package/dist/schema/nodes/lean-to-extension.js +114 -0
  133. package/dist/schema/nodes/level.d.ts +5 -2
  134. package/dist/schema/nodes/level.d.ts.map +1 -1
  135. package/dist/schema/nodes/level.js +9 -0
  136. package/dist/schema/nodes/lineset.d.ts +1 -1
  137. package/dist/schema/nodes/liquid-line.d.ts +1 -1
  138. package/dist/schema/nodes/measurement.d.ts +1 -1
  139. package/dist/schema/nodes/pipe-fitting.d.ts +9 -1
  140. package/dist/schema/nodes/pipe-fitting.d.ts.map +1 -1
  141. package/dist/schema/nodes/pipe-fitting.js +6 -2
  142. package/dist/schema/nodes/pipe-segment.d.ts +23 -1
  143. package/dist/schema/nodes/pipe-segment.d.ts.map +1 -1
  144. package/dist/schema/nodes/pipe-segment.js +20 -0
  145. package/dist/schema/nodes/pipe-trap.d.ts +1 -1
  146. package/dist/schema/nodes/ridge-vent.d.ts +1 -1
  147. package/dist/schema/nodes/ridge-vent.d.ts.map +1 -1
  148. package/dist/schema/nodes/ridge-vent.js +4 -1
  149. package/dist/schema/nodes/roof-segment-shape.d.ts +4 -0
  150. package/dist/schema/nodes/roof-segment-shape.d.ts.map +1 -1
  151. package/dist/schema/nodes/roof-segment-shape.js +64 -1
  152. package/dist/schema/nodes/roof-segment-walls.d.ts +3 -1
  153. package/dist/schema/nodes/roof-segment-walls.d.ts.map +1 -1
  154. package/dist/schema/nodes/roof-segment-walls.js +1 -1
  155. package/dist/schema/nodes/roof-segment.d.ts +41 -1
  156. package/dist/schema/nodes/roof-segment.d.ts.map +1 -1
  157. package/dist/schema/nodes/roof-segment.js +79 -2
  158. package/dist/schema/nodes/roof.d.ts +22 -1
  159. package/dist/schema/nodes/roof.d.ts.map +1 -1
  160. package/dist/schema/nodes/roof.js +14 -0
  161. package/dist/schema/nodes/scan.d.ts +19 -2
  162. package/dist/schema/nodes/scan.d.ts.map +1 -1
  163. package/dist/schema/nodes/scan.js +11 -1
  164. package/dist/schema/nodes/shelf.d.ts +2 -2
  165. package/dist/schema/nodes/site.d.ts +1 -1
  166. package/dist/schema/nodes/skylight.d.ts +1 -1
  167. package/dist/schema/nodes/slab.d.ts +1 -1
  168. package/dist/schema/nodes/solar-panel.d.ts +1 -1
  169. package/dist/schema/nodes/spawn.d.ts +1 -1
  170. package/dist/schema/nodes/stair-segment.d.ts +1 -1
  171. package/dist/schema/nodes/stair.d.ts +1 -1
  172. package/dist/schema/nodes/structural-grid.d.ts +1 -1
  173. package/dist/schema/nodes/turbine-vent.d.ts +7 -1
  174. package/dist/schema/nodes/turbine-vent.d.ts.map +1 -1
  175. package/dist/schema/nodes/turbine-vent.js +2 -0
  176. package/dist/schema/nodes/wall.d.ts +4 -4
  177. package/dist/schema/nodes/wall.d.ts.map +1 -1
  178. package/dist/schema/nodes/wall.js +7 -1
  179. package/dist/schema/nodes/window.d.ts +10 -3
  180. package/dist/schema/nodes/window.d.ts.map +1 -1
  181. package/dist/schema/nodes/window.js +4 -0
  182. package/dist/schema/nodes/zone.d.ts +2 -2
  183. package/dist/schema/nodes/zone.js +1 -1
  184. package/dist/schema/types.d.ts +485 -109
  185. package/dist/schema/types.d.ts.map +1 -1
  186. package/dist/schema/types.js +27 -1
  187. package/dist/services/hosting.d.ts +2 -2
  188. package/dist/services/hosting.d.ts.map +1 -1
  189. package/dist/services/hosting.js +4 -4
  190. package/dist/services/index.d.ts +2 -2
  191. package/dist/services/index.d.ts.map +1 -1
  192. package/dist/services/index.js +2 -2
  193. package/dist/services/storey.d.ts +3 -10
  194. package/dist/services/storey.d.ts.map +1 -1
  195. package/dist/services/storey.js +45 -15
  196. package/dist/services/system-graph.d.ts +11 -0
  197. package/dist/services/system-graph.d.ts.map +1 -1
  198. package/dist/services/system-graph.js +35 -5
  199. package/dist/store/actions/node-actions.d.ts +15 -4
  200. package/dist/store/actions/node-actions.d.ts.map +1 -1
  201. package/dist/store/actions/node-actions.js +458 -19
  202. package/dist/store/history-control.d.ts +5 -0
  203. package/dist/store/history-control.d.ts.map +1 -1
  204. package/dist/store/history-control.js +68 -6
  205. package/dist/store/history-invalidation.d.ts +3 -0
  206. package/dist/store/history-invalidation.d.ts.map +1 -0
  207. package/dist/store/history-invalidation.js +72 -0
  208. package/dist/store/scene-hydration.d.ts +5 -0
  209. package/dist/store/scene-hydration.d.ts.map +1 -0
  210. package/dist/store/scene-hydration.js +57 -0
  211. package/dist/store/use-scene.d.ts +3 -0
  212. package/dist/store/use-scene.d.ts.map +1 -1
  213. package/dist/store/use-scene.js +407 -227
  214. package/dist/systems/elevator/elevator-service.d.ts.map +1 -1
  215. package/dist/systems/elevator/elevator-service.js +16 -11
  216. package/dist/systems/roof/roof-elevation-system.d.ts +3 -0
  217. package/dist/systems/roof/roof-elevation-system.d.ts.map +1 -0
  218. package/dist/systems/roof/roof-elevation-system.js +94 -0
  219. package/dist/systems/roof/roof-elevation.d.ts +4 -0
  220. package/dist/systems/roof/roof-elevation.d.ts.map +1 -0
  221. package/dist/systems/roof/roof-elevation.js +95 -0
  222. package/dist/systems/roof/roof-footprint.d.ts +17 -0
  223. package/dist/systems/roof/roof-footprint.d.ts.map +1 -0
  224. package/dist/systems/roof/roof-footprint.js +83 -0
  225. package/dist/systems/slab/slab-support.d.ts +0 -31
  226. package/dist/systems/slab/slab-support.d.ts.map +1 -1
  227. package/dist/systems/slab/slab-support.js +26 -4
  228. package/dist/systems/stair/stair-flight.d.ts +17 -0
  229. package/dist/systems/stair/stair-flight.d.ts.map +1 -0
  230. package/dist/systems/stair/stair-flight.js +27 -0
  231. package/dist/systems/stair/stair-opening-preview.d.ts +1556 -1328
  232. package/dist/systems/stair/stair-opening-preview.d.ts.map +1 -1
  233. package/dist/systems/stair/stair-opening-system.d.ts +1 -0
  234. package/dist/systems/stair/stair-opening-system.d.ts.map +1 -1
  235. package/dist/systems/stair/stair-opening-system.js +93 -96
  236. package/dist/systems/stair/stair-rise.js +21 -20
  237. package/dist/systems/wall/wall-curve.d.ts +1 -0
  238. package/dist/systems/wall/wall-curve.d.ts.map +1 -1
  239. package/dist/systems/wall/wall-curve.js +73 -0
  240. package/dist/systems/wall/wall-footprint.d.ts +1 -0
  241. package/dist/systems/wall/wall-footprint.d.ts.map +1 -1
  242. package/dist/systems/wall/wall-footprint.js +1 -0
  243. package/dist/systems/wall/wall-mitering.d.ts.map +1 -1
  244. package/dist/systems/wall/wall-mitering.js +88 -9
  245. package/dist/systems/wall/wall-topology.d.ts +53 -0
  246. package/dist/systems/wall/wall-topology.d.ts.map +1 -0
  247. package/dist/systems/wall/wall-topology.js +414 -0
  248. package/dist/utils/clone-scene-graph.d.ts +2 -0
  249. package/dist/utils/clone-scene-graph.d.ts.map +1 -1
  250. package/dist/utils/clone-scene-graph.js +39 -2
  251. package/dist/utils/scene-migrations.d.ts +1 -0
  252. package/dist/utils/scene-migrations.d.ts.map +1 -1
  253. package/dist/utils/scene-migrations.js +1 -0
  254. package/dist/utils/vertical-scene-migration.d.ts +13 -0
  255. package/dist/utils/vertical-scene-migration.d.ts.map +1 -0
  256. package/dist/utils/vertical-scene-migration.js +179 -0
  257. package/dist/validation/validate-build-json.d.ts +3 -0
  258. package/dist/validation/validate-build-json.d.ts.map +1 -1
  259. package/dist/validation/validate-build-json.js +49 -2
  260. package/package.json +10 -3
  261. package/dist/systems/elevator/elevator-runtime-system.d.ts +0 -2
  262. package/dist/systems/elevator/elevator-runtime-system.d.ts.map +0 -1
  263. package/dist/systems/elevator/elevator-runtime-system.js +0 -8
@@ -0,0 +1,114 @@
1
+ import dedent from 'dedent';
2
+ import { z } from 'zod';
3
+ import { BaseNode, nodeType, objectId } from '../base';
4
+ import { ColumnNode } from './column';
5
+ import { RoofNode } from './roof';
6
+ import { SlabNode } from './slab';
7
+ export const LeanToConnectionMode = z.enum(['auto', 'manual']);
8
+ export const LeanToCanopyForm = z.enum(['mono', 'gable', 'butterfly']);
9
+ export const LeanToHostKind = z.enum(['wall', 'slab-edge', 'freestanding', 'conical-roof']);
10
+ export const LeanToRoofEdge = z.enum(['+X', '-X', '+Z', '-Z']);
11
+ export const LeanToResizeLock = z.enum([
12
+ 'preserve-high-edge',
13
+ 'preserve-low-edge',
14
+ 'preserve-pitch',
15
+ ]);
16
+ export const LeanToEndCondition = z.enum(['open', 'wall-abutment', 'joined']);
17
+ export const LeanToFramingStrategy = z.enum(['hidden', 'rafters', 'purlins', 'covering-specific']);
18
+ export const LeanToHighSideMode = z.enum(['wall-ledger', 'independent-high-beam']);
19
+ export const LeanToPostLayoutMode = z.enum(['count', 'target-spacing']);
20
+ export const LeanToFootingStyle = z.enum(['none', 'base-plate', 'concrete-pad']);
21
+ export const LeanToCoveringType = z.enum(['generic', 'shingle', 'metal-panel']);
22
+ const LeanToOmittedPostSlot = z.object({
23
+ side: z.enum(['low', 'high']),
24
+ index: z.number().int(),
25
+ layoutCount: z.number().int().min(1),
26
+ });
27
+ const DEFAULT_LOW_EDGE_HEIGHT = 2.7 - 3 * Math.tan((5 * Math.PI) / 180);
28
+ const DEFAULT_LEAN_TO_POST_SPACING = 3;
29
+ export const LeanToExtensionNode = BaseNode.extend({
30
+ id: objectId('leanto'),
31
+ type: nodeType('lean-to-extension'),
32
+ position: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
33
+ rotation: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
34
+ children: z.array(z.union([ColumnNode.shape.id, RoofNode.shape.id])).default([]),
35
+ canopyForm: LeanToCanopyForm.default('mono'),
36
+ hostKind: LeanToHostKind.default('wall'),
37
+ hostHeightOffset: z.number().min(-10).max(10).default(0),
38
+ hostSlabId: SlabNode.shape.id.optional(),
39
+ hostSlabEdgeIndex: z.number().int().min(0).optional(),
40
+ hostSlabEdgeT: z.number().min(0).max(1).optional(),
41
+ span: z.number().min(0.5).max(100).default(4),
42
+ autoSpan: z.boolean().default(true),
43
+ projection: z.number().min(0.5).max(10).default(2.5),
44
+ spanArcCenterZ: z
45
+ .number()
46
+ .optional()
47
+ .describe('Local-Z of the host wall arc center in the lean-to local frame (the crown sits on the local Z axis, so center X = 0). Derived from the host wall arc; absent for straight walls.'),
48
+ spanArcRadius: z
49
+ .number()
50
+ .optional()
51
+ .describe("The host wall's true arc radius, in metres. Derived from the host wall arc; absent for straight walls."),
52
+ highEdgeHeight: z.number().min(0.8).max(10).default(2.8),
53
+ lowEdgeHeight: z.number().min(0.2).max(10).default(DEFAULT_LOW_EDGE_HEIGHT),
54
+ pitch: z.number().min(1).max(45).default(10),
55
+ resizeLock: LeanToResizeLock.default('preserve-high-edge'),
56
+ leftEndCondition: LeanToEndCondition.default('open'),
57
+ rightEndCondition: LeanToEndCondition.default('open'),
58
+ autoMiterCorners: z.boolean().default(true),
59
+ sideFlashing: z.boolean().default(true),
60
+ flashingProjection: z.number().min(0.01).max(0.5).default(0.025),
61
+ flashingHeight: z.number().min(0.03).max(0.5).default(0.14),
62
+ slots: z.record(z.string(), z.string()).optional(),
63
+ highSideMode: LeanToHighSideMode.default('wall-ledger'),
64
+ ledgerVerticalOffset: z.number().min(-1).max(1).default(0),
65
+ lowBeamInset: z.number().min(0).max(2).default(0),
66
+ gutterEnabled: z.boolean().default(true),
67
+ gutterProfile: z.enum(['k-style', 'half-round', 'box']).default('k-style'),
68
+ gutterSize: z.number().min(0.04).max(0.3).default(0.13),
69
+ downspoutEnabled: z.boolean().default(true),
70
+ downspoutPosition: z.number().min(-1).max(1).default(1),
71
+ connectionMode: LeanToConnectionMode.default('auto'),
72
+ hostRoofId: RoofNode.shape.id.optional(),
73
+ hostRoofSegmentId: z.string().optional(),
74
+ hostRoofEdge: LeanToRoofEdge.optional(),
75
+ hostRoofEdgeRange: z.tuple([z.number().min(0).max(1), z.number().min(0).max(1)]).optional(),
76
+ connectionOffset: z.number().min(-1).max(1).default(0),
77
+ connectionInset: z.number().min(0).max(10).default(0),
78
+ matchHostRoofMaterial: z.boolean().default(true),
79
+ matchHostRoofStructure: z.boolean().default(true),
80
+ roofThickness: z.number().min(0.02).max(0.5).default(0.1),
81
+ shingleThickness: z.number().min(0).max(0.5).default(0.025),
82
+ highOverhang: z.number().min(0).max(1.5).default(0),
83
+ lowOverhang: z.number().min(0).max(1.5).default(0.25),
84
+ leftOverhang: z.number().min(0).max(1.5).default(0.15),
85
+ rightOverhang: z.number().min(0).max(1.5).default(0.15),
86
+ coveringType: LeanToCoveringType.default('generic'),
87
+ beamWidth: z.number().min(0.05).max(0.6).default(0.16),
88
+ beamHeight: z.number().min(0.05).max(0.8).default(0.24),
89
+ ledgerDepth: z.number().min(0.03).max(0.5).default(0.1),
90
+ ledgerHeight: z.number().min(0.05).max(0.8).default(0.18),
91
+ rafterWidth: z.number().min(0.03).max(0.4).default(0.08),
92
+ rafterHeight: z.number().min(0.03).max(0.5).default(0.14),
93
+ rafterSpacing: z.number().min(0.2).max(3).default(1.2),
94
+ rafterEndInset: z.number().min(0).max(3).default(0),
95
+ framingStrategy: LeanToFramingStrategy.default('rafters'),
96
+ purlinWidth: z.number().min(0.03).max(0.4).default(0.08),
97
+ purlinHeight: z.number().min(0.03).max(0.5).default(0.1),
98
+ purlinSpacing: z.number().min(0.2).max(3).default(0.8),
99
+ postWidth: z.number().min(0.05).max(0.6).default(0.16),
100
+ postDepth: z.number().min(0.05).max(0.6).default(0.16),
101
+ postCount: z.number().int().min(2).max(20).default(3),
102
+ postLayoutMode: LeanToPostLayoutMode.default('target-spacing'),
103
+ postSpacing: z.number().min(0.3).max(10).default(DEFAULT_LEAN_TO_POST_SPACING),
104
+ postInset: z.number().min(0).max(3).default(0),
105
+ omittedPostSlots: z.array(LeanToOmittedPostSlot).default([]),
106
+ postBracing: z.enum(['none', 'knee']).default('none'),
107
+ footingStyle: LeanToFootingStyle.default('none'),
108
+ }).describe(dedent `
109
+ Open parametric canopy.
110
+ The high edge can attach to a wall, attach to an upper slab edge, stand on an independent
111
+ high beam, or wrap around a conical roof's cylindrical base. Attached canopies use a mono-pitch
112
+ roof. Freestanding canopies can use a mono-pitch, gable, or butterfly roof with managed columns,
113
+ framing, gutters, and downspouts.
114
+ `);
@@ -1,4 +1,6 @@
1
1
  import { z } from 'zod';
2
+ export declare const DEFAULT_LEVEL_BASE_ELEVATION = 0;
3
+ export declare function normalizeLevelBaseElevation(value: unknown): number;
2
4
  export declare const LevelNode: z.ZodObject<{
3
5
  object: z.ZodDefault<z.ZodLiteral<"node">>;
4
6
  name: z.ZodOptional<z.ZodString>;
@@ -14,11 +16,12 @@ export declare const LevelNode: z.ZodObject<{
14
16
  fov: z.ZodOptional<z.ZodNumber>;
15
17
  zoom: z.ZodOptional<z.ZodNumber>;
16
18
  }, z.core.$strip>>;
17
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
19
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
18
20
  id: z.ZodDefault<z.ZodTemplateLiteral<`level_${string}`>>;
19
21
  type: z.ZodDefault<z.ZodLiteral<"level">>;
20
- children: z.ZodDefault<z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<`item_${string}` | `ceiling_${string}` | `column_${string}` | `wall_${string}` | `fence_${string}` | `construction-dimension_${string}` | `structural-grid_${string}` | `zone_${string}` | `slab_${string}` | `roof_${string}` | `stair_${string}` | `scan_${string}` | `guide_${string}` | `measurement_${string}` | `spawn_${string}` | `shelf_${string}` | `duct-segment_${string}` | `duct-fitting_${string}` | `duct-terminal_${string}` | `hvac-equipment_${string}` | `lineset_${string}` | `liquid-line_${string}` | `pipe-segment_${string}` | `pipe-fitting_${string}` | `pipe-trap_${string}`, string>>>>;
22
+ children: z.ZodDefault<z.ZodArray<z.ZodPipe<z.ZodString, z.ZodTransform<`item_${string}` | `block_${string}` | `ceiling_${string}` | `column_${string}` | `wall_${string}` | `roof_${string}` | `slab_${string}` | `fence_${string}` | `construction-dimension_${string}` | `structural-grid_${string}` | `zone_${string}` | `stair_${string}` | `scan_${string}` | `guide_${string}` | `measurement_${string}` | `spawn_${string}` | `shelf_${string}` | `duct-segment_${string}` | `duct-fitting_${string}` | `duct-terminal_${string}` | `hvac-equipment_${string}` | `lineset_${string}` | `liquid-line_${string}` | `pipe-segment_${string}` | `pipe-fitting_${string}` | `pipe-trap_${string}`, string>>>>;
21
23
  level: z.ZodDefault<z.ZodNumber>;
24
+ baseElevation: z.ZodDefault<z.ZodNumber>;
22
25
  height: z.ZodOptional<z.ZodNumber>;
23
26
  }, z.core.$strip>;
24
27
  export type LevelNode = z.infer<typeof LevelNode>;
@@ -1 +1 @@
1
- {"version":3,"file":"level.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/level.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAyDvB,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;iBAqBrB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAA"}
1
+ {"version":3,"file":"level.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/level.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AA2DvB,eAAO,MAAM,4BAA4B,IAAI,CAAA;AAE7C,wBAAgB,2BAA2B,CAAC,KAAK,EAAE,OAAO,GAAG,MAAM,CAElE;AAED,eAAO,MAAM,SAAS;;;;;;;;;;;;;;;;;;;;;;iBA0BrB,CAAA;AAED,MAAM,MAAM,SAAS,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,SAAS,CAAC,CAAA"}
@@ -2,6 +2,10 @@ import dedent from 'dedent';
2
2
  import { z } from 'zod';
3
3
  import { BaseNode, nodeType, objectId } from '../base';
4
4
  const LevelChildId = z.string().transform((id) => id);
5
+ export const DEFAULT_LEVEL_BASE_ELEVATION = 0;
6
+ export function normalizeLevelBaseElevation(value) {
7
+ return typeof value === 'number' && Number.isFinite(value) ? value : DEFAULT_LEVEL_BASE_ELEVATION;
8
+ }
5
9
  export const LevelNode = BaseNode.extend({
6
10
  id: objectId('level'),
7
11
  type: nodeType('level'),
@@ -10,6 +14,10 @@ export const LevelNode = BaseNode.extend({
10
14
  children: z.array(LevelChildId).default([]),
11
15
  // Specific props
12
16
  level: z.number().default(0),
17
+ baseElevation: z
18
+ .number()
19
+ .default(DEFAULT_LEVEL_BASE_ELEVATION)
20
+ .describe("Additive Y offset in meters applied above this level's computed stack position."),
13
21
  /**
14
22
  * Stored storey height in meters (floor-to-floor). No zod default on
15
23
  * purpose: absence marks unmigrated legacy data and gates the load-time
@@ -20,5 +28,6 @@ export const LevelNode = BaseNode.extend({
20
28
  Level node - used to represent a level in the building
21
29
  - children: array of architectural, equipment, and MEP distribution nodes
22
30
  - level: level number
31
+ - baseElevation: additive Y offset in meters above the computed stack position
23
32
  - height: storey height in meters (floor-to-floor); absent only on unmigrated legacy data
24
33
  `);
@@ -29,7 +29,7 @@ export declare const LinesetNode: z.ZodObject<{
29
29
  fov: z.ZodOptional<z.ZodNumber>;
30
30
  zoom: z.ZodOptional<z.ZodNumber>;
31
31
  }, z.core.$strip>>;
32
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
32
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
33
33
  id: z.ZodDefault<z.ZodTemplateLiteral<`lineset_${string}`>>;
34
34
  type: z.ZodDefault<z.ZodLiteral<"lineset">>;
35
35
  path: z.ZodArray<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
@@ -23,7 +23,7 @@ export declare const LiquidLineNode: z.ZodObject<{
23
23
  fov: z.ZodOptional<z.ZodNumber>;
24
24
  zoom: z.ZodOptional<z.ZodNumber>;
25
25
  }, z.core.$strip>>;
26
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
26
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
27
27
  id: z.ZodDefault<z.ZodTemplateLiteral<`liquid-line_${string}`>>;
28
28
  type: z.ZodDefault<z.ZodLiteral<"liquid-line">>;
29
29
  path: z.ZodArray<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
@@ -206,7 +206,7 @@ export declare const MeasurementNode: z.ZodObject<{
206
206
  fov: z.ZodOptional<z.ZodNumber>;
207
207
  zoom: z.ZodOptional<z.ZodNumber>;
208
208
  }, z.core.$strip>>;
209
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
209
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
210
210
  id: z.ZodDefault<z.ZodTemplateLiteral<`measurement_${string}`>>;
211
211
  type: z.ZodDefault<z.ZodLiteral<"measurement">>;
212
212
  measurement: z.ZodDiscriminatedUnion<[z.ZodObject<{
@@ -27,7 +27,7 @@ export declare const PipeFittingNode: z.ZodObject<{
27
27
  fov: z.ZodOptional<z.ZodNumber>;
28
28
  zoom: z.ZodOptional<z.ZodNumber>;
29
29
  }, z.core.$strip>>;
30
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
30
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
31
31
  id: z.ZodDefault<z.ZodTemplateLiteral<`pipe-fitting_${string}`>>;
32
32
  type: z.ZodDefault<z.ZodLiteral<"pipe-fitting">>;
33
33
  position: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
@@ -35,12 +35,20 @@ export declare const PipeFittingNode: z.ZodObject<{
35
35
  fittingType: z.ZodDefault<z.ZodEnum<{
36
36
  elbow: "elbow";
37
37
  cross: "cross";
38
+ reducer: "reducer";
39
+ "end-cap": "end-cap";
40
+ coupling: "coupling";
38
41
  wye: "wye";
39
42
  "sanitary-tee": "sanitary-tee";
43
+ cleanout: "cleanout";
40
44
  }>>;
41
45
  angle: z.ZodDefault<z.ZodNumber>;
42
46
  diameter: z.ZodDefault<z.ZodNumber>;
43
47
  diameter2: z.ZodDefault<z.ZodNumber>;
48
+ cleanoutStyle: z.ZodDefault<z.ZodEnum<{
49
+ end: "end";
50
+ inline: "inline";
51
+ }>>;
44
52
  pipeMaterial: z.ZodDefault<z.ZodEnum<{
45
53
  pvc: "pvc";
46
54
  abs: "abs";
@@ -1 +1 @@
1
- {"version":3,"file":"pipe-fitting.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/pipe-fitting.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8B3B,CAAA;AACD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAC7D,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA"}
1
+ {"version":3,"file":"pipe-fitting.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/pipe-fitting.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB;;;;;;;;;;;;GAYG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAkC3B,CAAA;AACD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAC7D,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA"}
@@ -21,7 +21,9 @@ export const PipeFittingNode = BaseNode.extend({
21
21
  position: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
22
22
  // XYZ euler radians.
23
23
  rotation: z.tuple([z.number(), z.number(), z.number()]).default([0, 0, 0]),
24
- fittingType: z.enum(['elbow', 'wye', 'sanitary-tee', 'cross']).default('elbow'),
24
+ fittingType: z
25
+ .enum(['elbow', 'wye', 'sanitary-tee', 'cross', 'end-cap', 'cleanout', 'reducer', 'coupling'])
26
+ .default('elbow'),
25
27
  // Elbow turn in degrees — DWV bends ship as 22.5 / 45 / 90 ("long
26
28
  // sweep" for drains); adjustable range matches the duct elbow. 0° is a
27
29
  // straight coupling — what an elbow flattens to when its run is dragged
@@ -31,13 +33,15 @@ export const PipeFittingNode = BaseNode.extend({
31
33
  diameter: z.number().min(1.25).max(8).default(2),
32
34
  // Branch collar size (wye / sanitary-tee).
33
35
  diameter2: z.number().min(1.25).max(8).default(2),
36
+ cleanoutStyle: z.enum(['end', 'inline']).default('end'),
34
37
  pipeMaterial: z.enum(['pvc', 'abs', 'cast-iron']).default('pvc'),
35
38
  system: z.enum(['waste', 'vent']).default('waste'),
36
39
  }).describe(dedent `
37
40
  DWV pipe fitting - elbow (bend), wye (45° branch), sanitary tee (square branch), or cross (two opposed branches).
38
41
  - position: [x, y, z] level-local meters
39
42
  - rotation: [x, y, z] euler radians
40
- - fittingType: elbow | wye | sanitary-tee | cross
43
+ - fittingType: elbow | wye | sanitary-tee | cross | end-cap | cleanout | reducer | coupling
44
+ - cleanoutStyle: end (one flow port) or inline (two flow ports with a capped service branch)
41
45
  - angle: elbow turn in degrees (22.5 / 45 / 90 typical)
42
46
  - diameter: run size in inches; diameter2: branch collar size (both branches for a cross)
43
47
  - pipeMaterial: pvc | abs | cast-iron
@@ -28,10 +28,32 @@ export declare const PipeSegmentNode: z.ZodObject<{
28
28
  fov: z.ZodOptional<z.ZodNumber>;
29
29
  zoom: z.ZodOptional<z.ZodNumber>;
30
30
  }, z.core.$strip>>;
31
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
31
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
32
32
  id: z.ZodDefault<z.ZodTemplateLiteral<`pipe-segment_${string}`>>;
33
33
  type: z.ZodDefault<z.ZodLiteral<"pipe-segment">>;
34
34
  path: z.ZodArray<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
35
+ autoHangers: z.ZodOptional<z.ZodBoolean>;
36
+ hangerOverrides: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodObject<{
37
+ fraction: z.ZodOptional<z.ZodNumber>;
38
+ skipped: z.ZodOptional<z.ZodBoolean>;
39
+ hostId: z.ZodOptional<z.ZodString>;
40
+ }, z.core.$strip>>>;
41
+ hangerStyle: z.ZodOptional<z.ZodEnum<{
42
+ double: "double";
43
+ single: "single";
44
+ }>>;
45
+ hangerSpacing: z.ZodOptional<z.ZodNumber>;
46
+ hangerMaxReach: z.ZodOptional<z.ZodNumber>;
47
+ wallAttachment: z.ZodOptional<z.ZodObject<{
48
+ wallId: z.ZodDefault<z.ZodTemplateLiteral<`wall_${string}`>>;
49
+ side: z.ZodEnum<{
50
+ front: "front";
51
+ back: "back";
52
+ }>;
53
+ startUV: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
54
+ endUV: z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>;
55
+ offset: z.ZodNumber;
56
+ }, z.core.$strip>>;
35
57
  diameter: z.ZodDefault<z.ZodNumber>;
36
58
  pipeMaterial: z.ZodDefault<z.ZodEnum<{
37
59
  pvc: "pvc";
@@ -1 +1 @@
1
- {"version":3,"file":"pipe-segment.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/pipe-segment.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAoB3B,CAAA;AACD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAC7D,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA"}
1
+ {"version":3,"file":"pipe-segment.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/pipe-segment.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAIvB;;;;;;;;;;;;;GAaG;AACH,eAAO,MAAM,eAAe;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAuC3B,CAAA;AACD,MAAM,MAAM,eAAe,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,eAAe,CAAC,CAAA;AAC7D,MAAM,MAAM,iBAAiB,GAAG,eAAe,CAAC,IAAI,CAAC,CAAA"}
@@ -1,6 +1,7 @@
1
1
  import dedent from 'dedent';
2
2
  import { z } from 'zod';
3
3
  import { BaseNode, nodeType, objectId } from '../base';
4
+ import { HangerOverrides } from './hanger-overrides';
4
5
  /**
5
6
  * DWV pipe segment — drain / waste / vent runs in US residential
6
7
  * plumbing. Phase 2 of the distribution-system effort: the plumbing
@@ -20,6 +21,22 @@ export const PipeSegmentNode = BaseNode.extend({
20
21
  type: nodeType('pipe-segment'),
21
22
  // Polyline path in level-local meters. Minimum two points.
22
23
  path: z.array(z.tuple([z.number(), z.number(), z.number()])).min(2),
24
+ autoHangers: z.boolean().optional(),
25
+ hangerOverrides: HangerOverrides.optional(),
26
+ hangerStyle: z.enum(['single', 'double']).optional(),
27
+ hangerSpacing: z.number().finite().positive().optional(),
28
+ hangerMaxReach: z.number().finite().positive().optional(),
29
+ // Logical wall host for runs drafted on a wall. The path remains
30
+ // level-local; UV coordinates let wall edits reproject the run later.
31
+ wallAttachment: z
32
+ .object({
33
+ wallId: objectId('wall'),
34
+ side: z.enum(['front', 'back']),
35
+ startUV: z.tuple([z.number(), z.number()]),
36
+ endUV: z.tuple([z.number(), z.number()]),
37
+ offset: z.number().finite().nonnegative(),
38
+ })
39
+ .optional(),
23
40
  // Nominal pipe size in inches. Residential DWV: 1¼ (lav tailpiece) to
24
41
  // 4 (building drain); 6 covers oversized mains.
25
42
  diameter: z.number().min(1.25).max(8).default(2),
@@ -29,6 +46,9 @@ export const PipeSegmentNode = BaseNode.extend({
29
46
  system: z.enum(['waste', 'vent']).default('waste'),
30
47
  }).describe(dedent `
31
48
  DWV pipe segment - drain / waste / vent run as a polyline of 3D points.
49
+ - autoHangers: automatically attach supports to nearby walls or ceilings (off when absent)
50
+ - hangerSpacing: distance between supports in meters (default 1.5)
51
+ - hangerMaxReach: maximum centerline-to-host distance in meters (default 2)
32
52
  - path: list of [x, y, z] points in level-local meters (min 2; y may go below the floor)
33
53
  - diameter: nominal size in inches (1.5 / 2 / 3 / 4 typical residential)
34
54
  - pipeMaterial: pvc | abs | cast-iron
@@ -25,7 +25,7 @@ export declare const PipeTrapNode: z.ZodObject<{
25
25
  fov: z.ZodOptional<z.ZodNumber>;
26
26
  zoom: z.ZodOptional<z.ZodNumber>;
27
27
  }, z.core.$strip>>;
28
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
28
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
29
29
  id: z.ZodDefault<z.ZodTemplateLiteral<`pipe-trap_${string}`>>;
30
30
  type: z.ZodDefault<z.ZodLiteral<"pipe-trap">>;
31
31
  position: z.ZodDefault<z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>>;
@@ -20,7 +20,7 @@ export declare const RidgeVentNode: z.ZodObject<{
20
20
  fov: z.ZodOptional<z.ZodNumber>;
21
21
  zoom: z.ZodOptional<z.ZodNumber>;
22
22
  }, z.core.$strip>>;
23
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
23
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
24
24
  id: z.ZodDefault<z.ZodTemplateLiteral<`rvent_${string}`>>;
25
25
  type: z.ZodDefault<z.ZodLiteral<"ridge-vent">>;
26
26
  material: z.ZodOptional<z.ZodObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"ridge-vent.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/ridge-vent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,gBAAgB,CAAA;AAyBvB,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvB,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8BzB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAEzD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,eAAe,GAAG,aAAa,EAAE,CAkJrF;AAQD,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,eAAe,GAAG,aAAa,EAAE,CAiB3F;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,OAAO,EACb,aAAa,CAAC,EAAE,eAAe,CAAC,IAAI,CAAC,GACpC,IAAI,IAAI,aAAa,CAyBvB;AASD,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,GACzC,OAAO,IAAI,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,GAAG;IAChD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QAAE,aAAa,EAAE,OAAO,CAAA;KAAE,CAAA;CAC/D,CAEA;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,UAAU,GAAG,UAAU,CAAC,EAC9D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAUT"}
1
+ {"version":3,"file":"ridge-vent.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/ridge-vent.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAGvB,OAAO,EAIL,KAAK,eAAe,EAErB,MAAM,gBAAgB,CAAA;AAyBvB,MAAM,MAAM,aAAa,GAAG;IAC1B,IAAI,EAAE,MAAM,CAAA;IACZ,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IACvB,GAAG,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;CACtB,CAAA;AAED,eAAO,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA8BzB,CAAA;AAED,MAAM,MAAM,aAAa,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,aAAa,CAAC,CAAA;AAEzD,wBAAgB,2BAA2B,CAAC,OAAO,EAAE,eAAe,GAAG,aAAa,EAAE,CAwJrF;AAQD,wBAAgB,iCAAiC,CAAC,OAAO,EAAE,eAAe,GAAG,aAAa,EAAE,CAiB3F;AAED,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,OAAO,EACb,aAAa,CAAC,EAAE,eAAe,CAAC,IAAI,CAAC,GACpC,IAAI,IAAI,aAAa,CAyBvB;AASD,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,GACzC,OAAO,IAAI,IAAI,CAAC,eAAe,EAAE,UAAU,CAAC,GAAG;IAChD,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG;QAAE,aAAa,EAAE,OAAO,CAAA;KAAE,CAAA;CAC/D,CAEA;AAED,wBAAgB,sBAAsB,CACpC,OAAO,EAAE,IAAI,CAAC,eAAe,EAAE,IAAI,GAAG,UAAU,GAAG,UAAU,CAAC,EAC9D,KAAK,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC9B,OAAO,CAUT"}
@@ -56,8 +56,11 @@ export function getRidgeVentLinesForSegment(segment) {
56
56
  trim: UNTRIMMED_RIDGE_VENT_BOUNDS_TRIM,
57
57
  });
58
58
  const { width, depth, minX, maxX, minZ, maxZ } = bounds;
59
- if (segment.roofType === 'flat' || segment.roofType === 'shed')
59
+ if (segment.roofType === 'flat' ||
60
+ segment.roofType === 'shed' ||
61
+ segment.roofType === 'conical') {
60
62
  return [];
63
+ }
61
64
  const halfW = width / 2;
62
65
  const halfD = depth / 2;
63
66
  const ridgeZVisible = minZ <= 0 && maxZ >= 0;
@@ -4,6 +4,8 @@ export type RoofShapeFaceVertex = {
4
4
  y: number;
5
5
  z: number;
6
6
  };
7
+ export type RoofShapeEaveSide = '+X' | '-X' | '+Z' | '-Z';
8
+ export declare function getRoofShapeEaveSides(type: RoofType): RoofShapeEaveSide[];
7
9
  export type RoofShapeInsets = {
8
10
  iF?: number;
9
11
  iB?: number;
@@ -86,5 +88,7 @@ export declare function getRoofModuleFaces(input: {
86
88
  shapeRatios: RoofShapeRatios;
87
89
  excludeDutchEndSlopes?: boolean;
88
90
  dutchTopRakeThickness?: number;
91
+ conicalStartAngle?: number;
92
+ conicalSweepAngle?: number;
89
93
  }): RoofShapeFaceVertex[][];
90
94
  //# sourceMappingURL=roof-segment-shape.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"roof-segment-shape.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/roof-segment-shape.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"roof-segment-shape.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/roof-segment-shape.ts"],"names":[],"mappings":"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"}
@@ -1,4 +1,17 @@
1
1
  import { ROOF_SHAPE_DEFAULTS } from './roof-segment';
2
+ export function getRoofShapeEaveSides(type) {
3
+ switch (type) {
4
+ case 'conical':
5
+ return [];
6
+ case 'shed':
7
+ return ['+Z'];
8
+ case 'gable':
9
+ case 'gambrel':
10
+ return ['+Z', '-Z'];
11
+ default:
12
+ return ['+Z', '-Z', '+X', '-X'];
13
+ }
14
+ }
2
15
  export function getRoofShapeRatios(input) {
3
16
  return {
4
17
  gambrelLowerWidthRatio: input.gambrelLowerWidthRatio ?? ROOF_SHAPE_DEFAULTS.gambrelLowerWidthRatio,
@@ -61,7 +74,10 @@ export function getRoofShapeInsets(input) {
61
74
  let iB = 0;
62
75
  let iL = 0;
63
76
  let iR = 0;
64
- if (input.roofType === 'hip' || input.roofType === 'mansard' || input.roofType === 'dutch') {
77
+ if (input.roofType === 'hip' ||
78
+ input.roofType === 'mansard' ||
79
+ input.roofType === 'dutch' ||
80
+ input.roofType === 'conical') {
65
81
  iF = inset;
66
82
  iB = inset;
67
83
  iL = inset;
@@ -158,6 +174,53 @@ export function getDutchEndSlopeFaces(input) {
158
174
  export function getRoofModuleFaces(input) {
159
175
  const v = (x, y, z) => ({ x, y, z });
160
176
  const { iF = 0, iB = 0, iL = 0, iR = 0 } = input.insets;
177
+ if (input.type === 'conical') {
178
+ const startAngle = Number.isFinite(input.conicalStartAngle) ? input.conicalStartAngle : 0;
179
+ const requestedSweep = Number.isFinite(input.conicalSweepAngle)
180
+ ? input.conicalSweepAngle
181
+ : -Math.PI * 2;
182
+ const sweepAngle = Math.max(-Math.PI * 2, Math.min(Math.PI * 2, Math.abs(requestedSweep) < 1e-4 ? 1e-4 : requestedSweep));
183
+ const isFullCone = Math.abs(sweepAngle) >= Math.PI * 2 - 1e-4;
184
+ const radialSegments = isFullCone
185
+ ? 48
186
+ : Math.max(1, Math.ceil((48 * Math.abs(sweepAngle)) / (Math.PI * 2)));
187
+ const eaveRadius = Math.max(0.005, input.w / 2);
188
+ const radialInset = (iF + iB + iL + iR) / 4;
189
+ const baseRadius = Math.max(0.005, eaveRadius - radialInset);
190
+ const eaveY = input.wh;
191
+ const peak = v(0, input.wh + Math.max(0.001, input.rh), 0);
192
+ const ringPointCount = isFullCone ? radialSegments : radialSegments + 1;
193
+ const bottomRing = Array.from({ length: ringPointCount }, (_, index) => {
194
+ const angle = startAngle + (index / radialSegments) * sweepAngle;
195
+ return v(Math.cos(angle) * baseRadius, input.baseY, Math.sin(angle) * baseRadius);
196
+ });
197
+ const eaveRing = Array.from({ length: ringPointCount }, (_, index) => {
198
+ const angle = startAngle + (index / radialSegments) * sweepAngle;
199
+ return v(Math.cos(angle) * eaveRadius, eaveY, Math.sin(angle) * eaveRadius);
200
+ });
201
+ const bottomCenter = v(0, input.baseY, 0);
202
+ const eaveCenter = v(0, eaveY, 0);
203
+ const faces = [
204
+ isFullCone ? [...bottomRing].reverse() : [bottomCenter, ...[...bottomRing].reverse()],
205
+ ];
206
+ for (let index = 0; index < radialSegments; index += 1) {
207
+ const next = isFullCone ? (index + 1) % radialSegments : index + 1;
208
+ faces.push([bottomRing[index], bottomRing[next], eaveRing[next], eaveRing[index]]);
209
+ }
210
+ if (input.rh === 0) {
211
+ faces.push(isFullCone ? [...eaveRing].reverse() : [eaveCenter, ...[...eaveRing].reverse()]);
212
+ }
213
+ else {
214
+ for (let index = 0; index < radialSegments; index += 1) {
215
+ const next = isFullCone ? (index + 1) % radialSegments : index + 1;
216
+ faces.push([eaveRing[index], eaveRing[next], peak]);
217
+ }
218
+ }
219
+ if (!isFullCone) {
220
+ faces.push([bottomCenter, bottomRing[0], eaveRing[0], peak], [bottomCenter, peak, eaveRing.at(-1), bottomRing.at(-1)]);
221
+ }
222
+ return sweepAngle > 0 ? faces.map((face) => [...face].reverse()) : faces;
223
+ }
161
224
  const b1 = v(-input.w / 2 + iL, input.baseY, input.d / 2 - iF);
162
225
  const b2 = v(input.w / 2 - iR, input.baseY, input.d / 2 - iF);
163
226
  const b3 = v(input.w / 2 - iR, input.baseY, -input.d / 2 + iB);
@@ -14,7 +14,9 @@ import type { RoofSegmentNode } from './roof-segment';
14
14
  * (`getVol(wallThickness / 2, 0, 0, …)`): the volume is the segment
15
15
  * footprint extended outward by `wallThickness / 2`, which drops the eave
16
16
  * line by `(wallThickness / 2) · tanθ` and raises the ridge by the same
17
- * amount so the apex stays at `wallHeight + activeRh`.
17
+ * amount so the apex stays at `wallHeight + activeRh` unless the eave
18
+ * hits the CSG minimum. The base stays at 0; the eave is raised to at
19
+ * least 0.05 above it to avoid sinking the shell into the supporting wall.
18
20
  */
19
21
  export type RoofWallFaceId = 'front' | 'back' | 'right' | 'left';
20
22
  export type RoofSegmentWallFace = {
@@ -1 +1 @@
1
- {"version":3,"file":"roof-segment-walls.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/roof-segment-walls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAGrD;;;;;;;;;;;;;;;;GAgBG;AAEH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAA;AAEhE,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,cAAc,CAAA;IAClB,6CAA6C;IAC7C,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAA;IACX,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;CAC5B,CAAA;AAED,KAAK,iBAAiB,GAAG,IAAI,CAC3B,eAAe,EACf,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,YAAY,GAAG,eAAe,GAAG,OAAO,CAC1E,GACC,OAAO,CACL,IAAI,CACF,eAAe,EACb,wBAAwB,GACxB,yBAAyB,GACzB,wBAAwB,GACxB,yBAAyB,GACzB,oBAAoB,GACpB,qBAAqB,GACrB,uBAAuB,CAC1B,CACF,CAAA;AAqJH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,iBAAiB,EACvB,EAAE,EAAE,cAAc,GACjB,mBAAmB,CAUrB;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,iBAAiB,GAAG,mBAAmB,EAAE,CAStF;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,iBAAiB,EACvB,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAC9B;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAaxC;AA+CD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,iBAAiB,EACvB,EAAE,EAAE,cAAc,GACjB;IAAE,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAYnD;AAED,yEAAyE;AACzE,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,iBAAiB,EACvB,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAC9B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAO1B;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,MAAM,CAWR;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,MAAM,CASR;AAID;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,mBAAmB,EACzB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACzB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAwCjC"}
1
+ {"version":3,"file":"roof-segment-walls.d.ts","sourceRoot":"","sources":["../../../src/schema/nodes/roof-segment-walls.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,gBAAgB,CAAA;AAGrD;;;;;;;;;;;;;;;;;;GAkBG;AAEH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,MAAM,GAAG,OAAO,GAAG,MAAM,CAAA;AAEhE,MAAM,MAAM,mBAAmB,GAAG;IAChC,EAAE,EAAE,cAAc,CAAA;IAClB,6CAA6C;IAC7C,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAA;IAChC;;;;OAIG;IACH,GAAG,EAAE,MAAM,CAAA;IACX,2BAA2B;IAC3B,MAAM,EAAE,MAAM,CAAA;IACd;;;OAGG;IACH,OAAO,EAAE,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,CAAA;CAC5B,CAAA;AAED,KAAK,iBAAiB,GAAG,IAAI,CAC3B,eAAe,EACf,UAAU,GAAG,OAAO,GAAG,OAAO,GAAG,YAAY,GAAG,eAAe,GAAG,OAAO,CAC1E,GACC,OAAO,CACL,IAAI,CACF,eAAe,EACb,wBAAwB,GACxB,yBAAyB,GACzB,wBAAwB,GACxB,yBAAyB,GACzB,oBAAoB,GACpB,qBAAqB,GACrB,uBAAuB,CAC1B,CACF,CAAA;AAqJH,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,iBAAiB,EACvB,EAAE,EAAE,cAAc,GACjB,mBAAmB,CAUrB;AAED,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,iBAAiB,GAAG,mBAAmB,EAAE,CAStF;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,IAAI,EAAE,iBAAiB,EACvB,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAC9B;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAaxC;AA+CD;;;;;;;;;;;GAWG;AACH,wBAAgB,oBAAoB,CAClC,IAAI,EAAE,iBAAiB,EACvB,EAAE,EAAE,cAAc,GACjB;IAAE,MAAM,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAYnD;AAED,yEAAyE;AACzE,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,iBAAiB,EACvB,EAAE,EAAE,cAAc,EAClB,KAAK,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,GAC9B,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAO1B;AAED;;;;;;GAMG;AACH,wBAAgB,6BAA6B,CAC3C,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,GACb,MAAM,CAWR;AAED;;;;;GAKG;AACH,wBAAgB,8BAA8B,CAC5C,IAAI,EAAE,mBAAmB,EACzB,OAAO,EAAE,MAAM,EACf,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,EACf,QAAQ,EAAE,MAAM,GACf,MAAM,CASR;AAID;;;;;;;;;GASG;AACH,wBAAgB,uBAAuB,CACrC,IAAI,EAAE,mBAAmB,EACzB,CAAC,EAAE,MAAM,EACT,CAAC,EAAE,MAAM,EACT,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,EACd,IAAI,CAAC,EAAE;IAAE,KAAK,CAAC,EAAE,OAAO,CAAA;CAAE,GACzB;IAAE,CAAC,EAAE,MAAM,CAAC;IAAC,CAAC,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAwCjC"}
@@ -5,7 +5,7 @@ function getWallVolumeFrame(node) {
5
5
  const autoDrop = (wallThickness / 2) * tanTheta;
6
6
  const wV = Math.max(0.01, node.width + wallThickness);
7
7
  const dV = Math.max(0.01, node.depth + wallThickness);
8
- const eaveY = Math.max(0.01, node.wallHeight - autoDrop);
8
+ const eaveY = Math.max(0.05, node.wallHeight - autoDrop);
9
9
  let rh = activeRh;
10
10
  if (activeRh > 0) {
11
11
  rh = activeRh + autoDrop;
@@ -8,6 +8,7 @@ export declare const RoofType: z.ZodEnum<{
8
8
  gambrel: "gambrel";
9
9
  dutch: "dutch";
10
10
  mansard: "mansard";
11
+ conical: "conical";
11
12
  }>;
12
13
  export type RoofType = z.infer<typeof RoofType>;
13
14
  export declare const MIN_ROOF_SEGMENT_TRIM_SPAN = 0.1;
@@ -70,7 +71,7 @@ export declare const RoofSegmentNode: z.ZodObject<{
70
71
  fov: z.ZodOptional<z.ZodNumber>;
71
72
  zoom: z.ZodOptional<z.ZodNumber>;
72
73
  }, z.core.$strip>>;
73
- metadata: z.ZodDefault<z.ZodOptional<z.ZodJSONSchema>>;
74
+ metadata: z.ZodDefault<z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnknown>>>;
74
75
  id: z.ZodDefault<z.ZodTemplateLiteral<`rseg_${string}`>>;
75
76
  type: z.ZodDefault<z.ZodLiteral<"roof-segment">>;
76
77
  material: z.ZodOptional<z.ZodObject<{
@@ -215,9 +216,13 @@ export declare const RoofSegmentNode: z.ZodObject<{
215
216
  gambrel: "gambrel";
216
217
  dutch: "dutch";
217
218
  mansard: "mansard";
219
+ conical: "conical";
218
220
  }>>;
219
221
  width: z.ZodDefault<z.ZodNumber>;
220
222
  depth: z.ZodDefault<z.ZodNumber>;
223
+ conicalStartAngle: z.ZodOptional<z.ZodNumber>;
224
+ conicalSweepAngle: z.ZodOptional<z.ZodNumber>;
225
+ conicalFullCircle: z.ZodOptional<z.ZodBoolean>;
221
226
  trim: z.ZodDefault<z.ZodObject<{
222
227
  left: z.ZodDefault<z.ZodNumber>;
223
228
  right: z.ZodDefault<z.ZodNumber>;
@@ -242,6 +247,33 @@ export declare const RoofSegmentNode: z.ZodObject<{
242
247
  deckThickness: z.ZodDefault<z.ZodNumber>;
243
248
  overhang: z.ZodDefault<z.ZodNumber>;
244
249
  shingleThickness: z.ZodDefault<z.ZodNumber>;
250
+ arc: z.ZodOptional<z.ZodObject<{
251
+ centerX: z.ZodNumber;
252
+ centerZ: z.ZodNumber;
253
+ radius: z.ZodNumber;
254
+ }, z.core.$strip>>;
255
+ shedSideInfillSpan: z.ZodOptional<z.ZodNumber>;
256
+ shedSideInfillMinX: z.ZodOptional<z.ZodNumber>;
257
+ shedSideInfillMaxX: z.ZodOptional<z.ZodNumber>;
258
+ shedFootprintPieces: z.ZodOptional<z.ZodArray<z.ZodArray<z.ZodTuple<[z.ZodNumber, z.ZodNumber], null>>>>;
259
+ shedOpenEndSides: z.ZodOptional<z.ZodArray<z.ZodEnum<{
260
+ right: "right";
261
+ left: "left";
262
+ }>>>;
263
+ shedJointFrame: z.ZodOptional<z.ZodObject<{
264
+ position: z.ZodTuple<[z.ZodNumber, z.ZodNumber, z.ZodNumber], null>;
265
+ rotation: z.ZodNumber;
266
+ }, z.core.$strip>>;
267
+ shedJointOwnerId: z.ZodOptional<z.ZodString>;
268
+ shedJointNeighborIds: z.ZodOptional<z.ZodArray<z.ZodString>>;
269
+ shedJointScopeId: z.ZodOptional<z.ZodString>;
270
+ managedByParent: z.ZodDefault<z.ZodBoolean>;
271
+ wallShell: z.ZodDefault<z.ZodEnum<{
272
+ auto: "auto";
273
+ include: "include";
274
+ omit: "omit";
275
+ }>>;
276
+ shedInsetEndPanels: z.ZodDefault<z.ZodBoolean>;
245
277
  gambrelLowerWidthRatio: z.ZodDefault<z.ZodNumber>;
246
278
  gambrelLowerHeightRatio: z.ZodDefault<z.ZodNumber>;
247
279
  mansardSteepWidthRatio: z.ZodDefault<z.ZodNumber>;
@@ -254,6 +286,11 @@ export declare const RoofSegmentNode: z.ZodObject<{
254
286
  children: z.ZodDefault<z.ZodArray<z.ZodString>>;
255
287
  }, z.core.$strip>;
256
288
  export type RoofSegmentNode = z.infer<typeof RoofSegmentNode>;
289
+ export declare function getConicalRoofCoverage(node: Pick<RoofSegmentNode, 'conicalFullCircle' | 'conicalStartAngle' | 'conicalSweepAngle'>): {
290
+ fullCircle: boolean;
291
+ startAngle: number;
292
+ sweepAngle: number;
293
+ };
257
294
  export declare function normalizeRoofSegmentTrim(node: Pick<RoofSegmentNode, 'width' | 'depth'> & {
258
295
  trim?: Partial<RoofSegmentTrim>;
259
296
  }): RoofSegmentTrim;
@@ -322,6 +359,9 @@ export type RoofSegmentVisibleTopBounds = {
322
359
  export declare function getRoofSegmentVisibleTopBounds(segment: RoofSegmentNode): RoofSegmentVisibleTopBounds;
323
360
  /** Segment-local surface height used by roof accessory placement and hit disambiguation. */
324
361
  export declare function getRoofSegmentSurfaceY(node: Pick<RoofSegmentNode, 'roofType' | 'width' | 'depth' | 'wallHeight'> & Parameters<typeof getSegmentSlopeFrame>[0], localX: number, localZ: number): number;
362
+ export declare function isBandedShedSegment(node: Pick<RoofSegmentNode, 'roofType' | 'arc'>): node is Pick<RoofSegmentNode, 'roofType' | 'arc'> & {
363
+ arc: NonNullable<RoofSegmentNode['arc']>;
364
+ };
325
365
  /**
326
366
  * Inverse of `getActiveRoofHeight` — recover the pitch a legacy
327
367
  * `roofHeight` value would correspond to. Used by the scene migration.