@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
@@ -45,7 +45,2791 @@ export declare function markDeckAttachedStairs(slabId: string, nodes: Record<str
45
45
  * Dirty every consumer of a slab's top or underside. Kept pure so committed
46
46
  * scene writes and live handle previews use the same dependency boundary.
47
47
  */
48
- export declare function markSlabChangeDependents(previous: SlabNode, next: SlabNode, nodes: Record<string, AnyNode>, markDirty: (id: AnyNodeId) => void): void;
48
+ export declare function markSlabChangeDependents(previous: SlabNode, next: SlabNode, nodes: Record<string, AnyNode>, markDirty: (id: AnyNodeId) => void, previousNodes?: Record<string, {
49
+ object: "node";
50
+ id: `site_${string}`;
51
+ parentId: string | null;
52
+ visible: boolean;
53
+ metadata: Record<string, unknown>;
54
+ children: string[];
55
+ polygon: {
56
+ type: "polygon";
57
+ points: [number, number][];
58
+ };
59
+ type: "site";
60
+ name?: string | undefined;
61
+ camera?: {
62
+ position: [number, number, number];
63
+ target: [number, number, number];
64
+ mode: "perspective" | "orthographic";
65
+ fov?: number | undefined;
66
+ zoom?: number | undefined;
67
+ } | undefined;
68
+ terrain?: {
69
+ type: "heightfield";
70
+ origin: [number, number];
71
+ spacing: number;
72
+ cols: number;
73
+ rows: number;
74
+ step: number;
75
+ heights: string;
76
+ } | undefined;
77
+ } | {
78
+ object: "node";
79
+ position: [number, number, number];
80
+ id: `building_${string}`;
81
+ parentId: string | null;
82
+ visible: boolean;
83
+ metadata: Record<string, unknown>;
84
+ rotation: [number, number, number];
85
+ children: (`elevator_${string}` | `level_${string}`)[];
86
+ type: "building";
87
+ name?: string | undefined;
88
+ camera?: {
89
+ position: [number, number, number];
90
+ target: [number, number, number];
91
+ mode: "perspective" | "orthographic";
92
+ fov?: number | undefined;
93
+ zoom?: number | undefined;
94
+ } | undefined;
95
+ } | {
96
+ object: "node";
97
+ position: [number, number, number];
98
+ id: `elevator_${string}`;
99
+ parentId: string | null;
100
+ visible: boolean;
101
+ metadata: Record<string, unknown>;
102
+ rotation: number;
103
+ width: number;
104
+ depth: number;
105
+ shaftWallThickness: number;
106
+ shaftStyle: "glass" | "solid";
107
+ cabHeight: number;
108
+ doorWidth: number;
109
+ doorHeight: number;
110
+ doorStyle: "center-opening" | "single-left" | "single-right";
111
+ doorPanelStyle: "glass-frame" | "solid-panel" | "segmented-panel";
112
+ fromLevelId: string | null;
113
+ toLevelId: string | null;
114
+ disabledLevelIds: string[];
115
+ serviceOnlyLevelIds: string[];
116
+ defaultLevelId: string | null;
117
+ speed: number;
118
+ doorDurationMs: number;
119
+ dwellMs: number;
120
+ type: "elevator";
121
+ name?: string | undefined;
122
+ camera?: {
123
+ position: [number, number, number];
124
+ target: [number, number, number];
125
+ mode: "perspective" | "orthographic";
126
+ fov?: number | undefined;
127
+ zoom?: number | undefined;
128
+ } | undefined;
129
+ slots?: Record<string, string> | undefined;
130
+ material?: {
131
+ id?: string | undefined;
132
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
133
+ properties?: {
134
+ color: string;
135
+ roughness: number;
136
+ metalness: number;
137
+ opacity: number;
138
+ transparent: boolean;
139
+ side: "front" | "back" | "double";
140
+ } | undefined;
141
+ texture?: {
142
+ url: string;
143
+ repeat?: [number, number] | undefined;
144
+ scale?: number | undefined;
145
+ } | undefined;
146
+ } | undefined;
147
+ materialPreset?: string | undefined;
148
+ shaftWidth?: number | undefined;
149
+ shaftDepth?: number | undefined;
150
+ servedLevelIds?: string[] | undefined;
151
+ } | {
152
+ object: "node";
153
+ id: `level_${string}`;
154
+ parentId: string | null;
155
+ visible: boolean;
156
+ metadata: Record<string, unknown>;
157
+ children: (`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}`)[];
158
+ level: number;
159
+ baseElevation: number;
160
+ type: "level";
161
+ name?: string | undefined;
162
+ camera?: {
163
+ position: [number, number, number];
164
+ target: [number, number, number];
165
+ mode: "perspective" | "orthographic";
166
+ fov?: number | undefined;
167
+ zoom?: number | undefined;
168
+ } | undefined;
169
+ height?: number | undefined;
170
+ } | {
171
+ object: "node";
172
+ position: [number, number, number];
173
+ id: `leanto_${string}`;
174
+ parentId: string | null;
175
+ visible: boolean;
176
+ metadata: Record<string, unknown>;
177
+ rotation: [number, number, number];
178
+ children: (`column_${string}` | `roof_${string}`)[];
179
+ pitch: number;
180
+ shingleThickness: number;
181
+ canopyForm: "gable" | "mono" | "butterfly";
182
+ hostKind: "wall" | "slab-edge" | "freestanding" | "conical-roof";
183
+ hostHeightOffset: number;
184
+ span: number;
185
+ autoSpan: boolean;
186
+ projection: number;
187
+ highEdgeHeight: number;
188
+ lowEdgeHeight: number;
189
+ resizeLock: "preserve-high-edge" | "preserve-low-edge" | "preserve-pitch";
190
+ leftEndCondition: "open" | "wall-abutment" | "joined";
191
+ rightEndCondition: "open" | "wall-abutment" | "joined";
192
+ autoMiterCorners: boolean;
193
+ sideFlashing: boolean;
194
+ flashingProjection: number;
195
+ flashingHeight: number;
196
+ highSideMode: "wall-ledger" | "independent-high-beam";
197
+ ledgerVerticalOffset: number;
198
+ lowBeamInset: number;
199
+ gutterEnabled: boolean;
200
+ gutterProfile: "box" | "k-style" | "half-round";
201
+ gutterSize: number;
202
+ downspoutEnabled: boolean;
203
+ downspoutPosition: number;
204
+ connectionMode: "manual" | "auto";
205
+ connectionOffset: number;
206
+ connectionInset: number;
207
+ matchHostRoofMaterial: boolean;
208
+ matchHostRoofStructure: boolean;
209
+ roofThickness: number;
210
+ highOverhang: number;
211
+ lowOverhang: number;
212
+ leftOverhang: number;
213
+ rightOverhang: number;
214
+ coveringType: "generic" | "shingle" | "metal-panel";
215
+ beamWidth: number;
216
+ beamHeight: number;
217
+ ledgerDepth: number;
218
+ ledgerHeight: number;
219
+ rafterWidth: number;
220
+ rafterHeight: number;
221
+ rafterSpacing: number;
222
+ rafterEndInset: number;
223
+ framingStrategy: "hidden" | "rafters" | "purlins" | "covering-specific";
224
+ purlinWidth: number;
225
+ purlinHeight: number;
226
+ purlinSpacing: number;
227
+ postWidth: number;
228
+ postDepth: number;
229
+ postCount: number;
230
+ postLayoutMode: "count" | "target-spacing";
231
+ postSpacing: number;
232
+ postInset: number;
233
+ omittedPostSlots: {
234
+ side: "low" | "high";
235
+ index: number;
236
+ layoutCount: number;
237
+ }[];
238
+ postBracing: "none" | "knee";
239
+ footingStyle: "none" | "base-plate" | "concrete-pad";
240
+ type: "lean-to-extension";
241
+ name?: string | undefined;
242
+ camera?: {
243
+ position: [number, number, number];
244
+ target: [number, number, number];
245
+ mode: "perspective" | "orthographic";
246
+ fov?: number | undefined;
247
+ zoom?: number | undefined;
248
+ } | undefined;
249
+ slots?: Record<string, string> | undefined;
250
+ hostSlabId?: `slab_${string}` | undefined;
251
+ hostSlabEdgeIndex?: number | undefined;
252
+ hostSlabEdgeT?: number | undefined;
253
+ spanArcCenterZ?: number | undefined;
254
+ spanArcRadius?: number | undefined;
255
+ hostRoofId?: `roof_${string}` | undefined;
256
+ hostRoofSegmentId?: string | undefined;
257
+ hostRoofEdge?: "+X" | "-X" | "+Z" | "-Z" | undefined;
258
+ hostRoofEdgeRange?: [number, number] | undefined;
259
+ } | {
260
+ object: "node";
261
+ position: [number, number, number];
262
+ id: `column_${string}`;
263
+ parentId: string | null;
264
+ visible: boolean;
265
+ metadata: Record<string, unknown>;
266
+ rotation: number;
267
+ height: number;
268
+ width: number;
269
+ depth: number;
270
+ baseHeight: number;
271
+ style: "plain" | "faceted" | "fluted" | "lathe-turned" | "dravidian-carved" | "cluster";
272
+ crossSection: "round" | "square" | "rectangular" | "octagonal" | "sixteen-sided";
273
+ radius: number;
274
+ edgeSoftness: number;
275
+ capitalHeight: number;
276
+ shaftProfile: "straight" | "tapered" | "bulged" | "baluster" | "hourglass";
277
+ shaftTaper: number;
278
+ shaftBulge: number;
279
+ shaftStartScale: number;
280
+ shaftEndScale: number;
281
+ shaftSegmentCount: number;
282
+ shaftTwistStep: number;
283
+ shaftCornerRadius: number;
284
+ shaftDetail: "fluted" | "lathe-turned" | "none" | "spiral" | "panelled";
285
+ baseStyle: "none" | "simple-square" | "round-rings" | "square-plinth" | "stepped-square" | "lotus" | "ribbed-lotus" | "panelled-pedestal";
286
+ baseWidthScale: number;
287
+ baseDepthScale: number;
288
+ baseTierCount: number;
289
+ baseStepSpread: number;
290
+ basePlinthHeightRatio: number;
291
+ baseRoundBandScale: number;
292
+ baseNeckScale: number;
293
+ baseRoundBandCount: number;
294
+ baseRibCount: number;
295
+ baseCarvingLevel: number;
296
+ basePanelInset: number;
297
+ capitalStyle: "none" | "simple" | "simple-slab" | "rounded" | "stepped" | "doric" | "volute" | "ionic-volute" | "leaf-carved" | "corinthian-leaf" | "south-indian-bracket" | "wood-bracket";
298
+ capitalWidthScale: number;
299
+ capitalDepthScale: number;
300
+ capitalTierCount: number;
301
+ capitalStepSpread: number;
302
+ capitalBandCount: number;
303
+ voluteSize: number;
304
+ voluteCount: number;
305
+ leafCount: number;
306
+ leafRows: number;
307
+ bracketDepth: number;
308
+ bracketTierCount: number;
309
+ pendantCount: number;
310
+ capitalCarvingLevel: number;
311
+ ringCount: number;
312
+ ringPlacement: "top" | "ends" | "even" | "bottom";
313
+ ringThickness: number;
314
+ ringSpread: number;
315
+ fluteCount: number;
316
+ fluteDepth: number;
317
+ fluteWidth: number;
318
+ spiralTwist: number;
319
+ spiralRibCount: number;
320
+ panelCount: number;
321
+ panelInsetDepth: number;
322
+ panelShape: "rectangle" | "arched" | "diamond";
323
+ latheRingCount: number;
324
+ latheRingSpacing: "top" | "ends" | "even" | "bottom";
325
+ carvingLevel: number;
326
+ carvingPlacement: "base" | "shaft" | "capital" | "all";
327
+ lowerBandEnabled: boolean;
328
+ lowerBandHeight: number;
329
+ lowerBandCarvingLevel: number;
330
+ dentilCount: number;
331
+ beadCount: number;
332
+ supportStyle: "vertical" | "a-frame" | "y-frame" | "v-frame" | "x-brace" | "k-brace" | "single-strut" | "tripod" | "trestle" | "portal-frame" | "box-frame";
333
+ braceWidth: number;
334
+ braceDepth: number;
335
+ braceBottomSpread: number;
336
+ braceTopSpread: number;
337
+ bracePlateEnabled: boolean;
338
+ type: "column";
339
+ name?: string | undefined;
340
+ camera?: {
341
+ position: [number, number, number];
342
+ target: [number, number, number];
343
+ mode: "perspective" | "orthographic";
344
+ fov?: number | undefined;
345
+ zoom?: number | undefined;
346
+ } | undefined;
347
+ supportSlabId?: string | undefined;
348
+ slots?: Record<string, string> | undefined;
349
+ material?: {
350
+ id?: string | undefined;
351
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
352
+ properties?: {
353
+ color: string;
354
+ roughness: number;
355
+ metalness: number;
356
+ opacity: number;
357
+ transparent: boolean;
358
+ side: "front" | "back" | "double";
359
+ } | undefined;
360
+ texture?: {
361
+ url: string;
362
+ repeat?: [number, number] | undefined;
363
+ scale?: number | undefined;
364
+ } | undefined;
365
+ } | undefined;
366
+ materialPreset?: string | undefined;
367
+ } | {
368
+ object: "node";
369
+ mode: "radius" | "linear" | "diameter" | "center-mark" | "chord" | "arc-length" | "angular" | "coordinate";
370
+ id: `construction-dimension_${string}`;
371
+ parentId: string | null;
372
+ visible: boolean;
373
+ metadata: Record<string, unknown>;
374
+ anchors: ([number, number, number] | {
375
+ kind: "feature";
376
+ reference: {
377
+ nodeId: string;
378
+ featureId: string;
379
+ parameters?: Record<string, string | number | boolean> | undefined;
380
+ };
381
+ fallback: [number, number, number];
382
+ })[];
383
+ baseline: {
384
+ origin: [number, number];
385
+ direction: [number, number];
386
+ };
387
+ chainMode: "point-to-point" | "continuous";
388
+ featureCount: number;
389
+ showCenterMark: boolean;
390
+ prefix: string;
391
+ suffix: string;
392
+ textOverride: string | null;
393
+ datumPolicy: "centerline" | "wall-face" | "structural-face" | "finish-face";
394
+ terminator: "architectural-tick" | "filled-arrow" | "open-arrow" | "dot";
395
+ textPosition: "above" | "centered";
396
+ imperialPrecision: "1" | "1/2" | "1/4" | "1/8" | "1/16";
397
+ metricNotation: "meters" | "millimeters";
398
+ extensionStartGap: number;
399
+ extensionOvershoot: number;
400
+ drawingType: "floor-plan" | "foundation-plan" | "reflected-ceiling-plan" | "roof-plan" | "site-plan";
401
+ drawingOverrides: {
402
+ drawingType: "floor-plan" | "foundation-plan" | "reflected-ceiling-plan" | "roof-plan" | "site-plan";
403
+ presentation: "omit" | "shown" | "controlled";
404
+ suppressedSegmentIndexes: number[];
405
+ }[];
406
+ controllingDimensionId: `construction-dimension_${string}` | null;
407
+ type: "construction-dimension";
408
+ name?: string | undefined;
409
+ camera?: {
410
+ position: [number, number, number];
411
+ target: [number, number, number];
412
+ mode: "perspective" | "orthographic";
413
+ fov?: number | undefined;
414
+ zoom?: number | undefined;
415
+ } | undefined;
416
+ } | {
417
+ object: "node";
418
+ position: [number, number, number];
419
+ id: `block_${string}`;
420
+ parentId: string | null;
421
+ visible: boolean;
422
+ metadata: Record<string, unknown>;
423
+ rotation: number;
424
+ children: `item_${string}`[];
425
+ slots: Record<string, string>;
426
+ topology: {
427
+ vertices: {
428
+ id: string;
429
+ position: [number, number, number];
430
+ }[];
431
+ edges: {
432
+ id: string;
433
+ vertexIds: [string, string];
434
+ }[];
435
+ faces: {
436
+ id: string;
437
+ vertexIds: string[];
438
+ materialSlot: string;
439
+ }[];
440
+ };
441
+ slotNames: Record<string, string>;
442
+ type: "block";
443
+ name?: string | undefined;
444
+ camera?: {
445
+ position: [number, number, number];
446
+ target: [number, number, number];
447
+ mode: "perspective" | "orthographic";
448
+ fov?: number | undefined;
449
+ zoom?: number | undefined;
450
+ } | undefined;
451
+ supportSlabId?: string | undefined;
452
+ } | {
453
+ object: "node";
454
+ id: `structural-grid_${string}`;
455
+ parentId: string | null;
456
+ visible: boolean;
457
+ metadata: Record<string, unknown>;
458
+ label: string;
459
+ start: [number, number];
460
+ end: [number, number];
461
+ showStartBubble: boolean;
462
+ showEndBubble: boolean;
463
+ type: "structural-grid";
464
+ name?: string | undefined;
465
+ camera?: {
466
+ position: [number, number, number];
467
+ target: [number, number, number];
468
+ mode: "perspective" | "orthographic";
469
+ fov?: number | undefined;
470
+ zoom?: number | undefined;
471
+ } | undefined;
472
+ } | {
473
+ object: "node";
474
+ id: `wall_${string}`;
475
+ parentId: string | null;
476
+ visible: boolean;
477
+ metadata: Record<string, unknown>;
478
+ children: (`item_${string}` | `door_${string}` | `window_${string}` | `leanto_${string}`)[];
479
+ start: [number, number];
480
+ end: [number, number];
481
+ frontSide: "unknown" | "interior" | "exterior";
482
+ backSide: "unknown" | "interior" | "exterior";
483
+ type: "wall";
484
+ name?: string | undefined;
485
+ camera?: {
486
+ position: [number, number, number];
487
+ target: [number, number, number];
488
+ mode: "perspective" | "orthographic";
489
+ fov?: number | undefined;
490
+ zoom?: number | undefined;
491
+ } | undefined;
492
+ height?: number | undefined;
493
+ supportSlabId?: string | undefined;
494
+ slots?: Record<string, string> | undefined;
495
+ material?: {
496
+ id?: string | undefined;
497
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
498
+ properties?: {
499
+ color: string;
500
+ roughness: number;
501
+ metalness: number;
502
+ opacity: number;
503
+ transparent: boolean;
504
+ side: "front" | "back" | "double";
505
+ } | undefined;
506
+ texture?: {
507
+ url: string;
508
+ repeat?: [number, number] | undefined;
509
+ scale?: number | undefined;
510
+ } | undefined;
511
+ } | undefined;
512
+ materialPreset?: string | undefined;
513
+ thickness?: number | undefined;
514
+ fillToTerrain?: boolean | undefined;
515
+ interiorMaterial?: {
516
+ id?: string | undefined;
517
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
518
+ properties?: {
519
+ color: string;
520
+ roughness: number;
521
+ metalness: number;
522
+ opacity: number;
523
+ transparent: boolean;
524
+ side: "front" | "back" | "double";
525
+ } | undefined;
526
+ texture?: {
527
+ url: string;
528
+ repeat?: [number, number] | undefined;
529
+ scale?: number | undefined;
530
+ } | undefined;
531
+ } | undefined;
532
+ interiorMaterialPreset?: string | undefined;
533
+ exteriorMaterial?: {
534
+ id?: string | undefined;
535
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
536
+ properties?: {
537
+ color: string;
538
+ roughness: number;
539
+ metalness: number;
540
+ opacity: number;
541
+ transparent: boolean;
542
+ side: "front" | "back" | "double";
543
+ } | undefined;
544
+ texture?: {
545
+ url: string;
546
+ repeat?: [number, number] | undefined;
547
+ scale?: number | undefined;
548
+ } | undefined;
549
+ } | undefined;
550
+ exteriorMaterialPreset?: string | undefined;
551
+ curveOffset?: number | undefined;
552
+ supportOffset?: number | undefined;
553
+ faceBands?: {
554
+ enabled: boolean;
555
+ count: number;
556
+ lowerHeight: number;
557
+ middleHeight: number;
558
+ upperHeight: number;
559
+ } | undefined;
560
+ skirting?: {
561
+ enabled: boolean;
562
+ sides: "interior" | "exterior" | "both";
563
+ height: number;
564
+ proud: number;
565
+ profile: "flat" | "bevel" | "triangle" | "cove" | "bullnose" | "base-modern" | "base-colonial" | "base-shoe" | "base-ogee" | "crown-cove" | "crown-ogee" | "crown-craftsman" | "crown-layered" | "rail-rounded" | "rail-ogee" | "rail-picture" | "rail-stepped";
566
+ offsetY?: number | undefined;
567
+ } | undefined;
568
+ crown?: {
569
+ enabled: boolean;
570
+ sides: "interior" | "exterior" | "both";
571
+ height: number;
572
+ proud: number;
573
+ profile: "flat" | "bevel" | "triangle" | "cove" | "bullnose" | "base-modern" | "base-colonial" | "base-shoe" | "base-ogee" | "crown-cove" | "crown-ogee" | "crown-craftsman" | "crown-layered" | "rail-rounded" | "rail-ogee" | "rail-picture" | "rail-stepped";
574
+ offsetY?: number | undefined;
575
+ } | undefined;
576
+ chairRail?: {
577
+ enabled: boolean;
578
+ sides: "interior" | "exterior" | "both";
579
+ height: number;
580
+ proud: number;
581
+ profile: "flat" | "bevel" | "triangle" | "cove" | "bullnose" | "base-modern" | "base-colonial" | "base-shoe" | "base-ogee" | "crown-cove" | "crown-ogee" | "crown-craftsman" | "crown-layered" | "rail-rounded" | "rail-ogee" | "rail-picture" | "rail-stepped";
582
+ offsetY?: number | undefined;
583
+ } | undefined;
584
+ } | {
585
+ object: "node";
586
+ id: `fence_${string}`;
587
+ parentId: string | null;
588
+ visible: boolean;
589
+ metadata: Record<string, unknown>;
590
+ color: string;
591
+ height: number;
592
+ baseHeight: number;
593
+ style: "slat" | "rail" | "privacy" | "horizontal";
594
+ baseStyle: "floating" | "grounded";
595
+ thickness: number;
596
+ postSpacing: number;
597
+ start: [number, number];
598
+ end: [number, number];
599
+ postSize: number;
600
+ topRailHeight: number;
601
+ groundClearance: number;
602
+ edgeInset: number;
603
+ slatGap: number;
604
+ postCap: "flat" | "none" | "pyramid";
605
+ showInfill: boolean;
606
+ type: "fence";
607
+ path?: [number, number][] | undefined;
608
+ name?: string | undefined;
609
+ camera?: {
610
+ position: [number, number, number];
611
+ target: [number, number, number];
612
+ mode: "perspective" | "orthographic";
613
+ fov?: number | undefined;
614
+ zoom?: number | undefined;
615
+ } | undefined;
616
+ supportSlabId?: string | undefined;
617
+ slots?: Record<string, string> | undefined;
618
+ material?: {
619
+ id?: string | undefined;
620
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
621
+ properties?: {
622
+ color: string;
623
+ roughness: number;
624
+ metalness: number;
625
+ opacity: number;
626
+ transparent: boolean;
627
+ side: "front" | "back" | "double";
628
+ } | undefined;
629
+ texture?: {
630
+ url: string;
631
+ repeat?: [number, number] | undefined;
632
+ scale?: number | undefined;
633
+ } | undefined;
634
+ } | undefined;
635
+ materialPreset?: string | undefined;
636
+ curveOffset?: number | undefined;
637
+ supportOffset?: number | undefined;
638
+ tangents?: ([number, number] | null)[] | undefined;
639
+ } | {
640
+ object: "node";
641
+ position: [number, number, number];
642
+ id: `cabinet_${string}`;
643
+ parentId: string | null;
644
+ visible: boolean;
645
+ metadata: Record<string, unknown>;
646
+ rotation: number;
647
+ children: (`cabinet_${string}` | `cabinet-module_${string}`)[];
648
+ width: number;
649
+ depth: number;
650
+ operationState: number;
651
+ runTier: "wall" | "base" | "tall";
652
+ withWaterfall: boolean;
653
+ withFinishedEnds: boolean;
654
+ carcassHeight: number;
655
+ plinthHeight: number;
656
+ toeKickDepth: number;
657
+ boardThickness: number;
658
+ countertopThickness: number;
659
+ countertopOverhang: number;
660
+ countertopBackOverhang: number;
661
+ withFinishedBack: boolean;
662
+ frontThickness: number;
663
+ frontGap: number;
664
+ frontStyle: "slab" | "shaker" | "raised-arch";
665
+ panelReady: boolean;
666
+ handleStyle: "none" | "bar" | "cutout" | "hole" | "knob";
667
+ handlePosition: "top" | "auto" | "center";
668
+ frontOverlay: "full" | "inset";
669
+ withBottomPanel: boolean;
670
+ showPlinth: boolean;
671
+ withCountertop: boolean;
672
+ type: "cabinet";
673
+ name?: string | undefined;
674
+ camera?: {
675
+ position: [number, number, number];
676
+ target: [number, number, number];
677
+ mode: "perspective" | "orthographic";
678
+ fov?: number | undefined;
679
+ zoom?: number | undefined;
680
+ } | undefined;
681
+ supportSlabId?: string | undefined;
682
+ slots?: Record<string, string> | undefined;
683
+ material?: {
684
+ id?: string | undefined;
685
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
686
+ properties?: {
687
+ color: string;
688
+ roughness: number;
689
+ metalness: number;
690
+ opacity: number;
691
+ transparent: boolean;
692
+ side: "front" | "back" | "double";
693
+ } | undefined;
694
+ texture?: {
695
+ url: string;
696
+ repeat?: [number, number] | undefined;
697
+ scale?: number | undefined;
698
+ } | undefined;
699
+ } | undefined;
700
+ materialPreset?: string | undefined;
701
+ barLedge?: {
702
+ edge: "back" | "right" | "left";
703
+ height: number;
704
+ depth: number;
705
+ } | undefined;
706
+ stack?: ({
707
+ type: "shelf";
708
+ id: string;
709
+ shelfCount?: number | undefined;
710
+ height?: number | undefined;
711
+ } | {
712
+ type: "drawer";
713
+ id: string;
714
+ drawerCount?: number | undefined;
715
+ height?: number | undefined;
716
+ } | {
717
+ type: "door";
718
+ id: string;
719
+ doorType?: "glass" | "double" | "single-left" | "single-right" | undefined;
720
+ shelfCount?: number | undefined;
721
+ height?: number | undefined;
722
+ } | {
723
+ type: "sink";
724
+ id: string;
725
+ sinkLayout?: "double" | "single" | "double-offset" | undefined;
726
+ height?: number | undefined;
727
+ } | {
728
+ type: "oven";
729
+ id: string;
730
+ height?: number | undefined;
731
+ } | {
732
+ type: "microwave";
733
+ id: string;
734
+ height?: number | undefined;
735
+ } | {
736
+ type: "dishwasher";
737
+ id: string;
738
+ height?: number | undefined;
739
+ } | {
740
+ type: "cooktop-gas";
741
+ id: string;
742
+ cooktopLayout?: "gas-2burner" | "gas-4burner" | "gas-5burner-wok" | "gas-6burner" | undefined;
743
+ cooktopBurnersOn?: boolean | undefined;
744
+ cooktopActiveBurners?: number[] | undefined;
745
+ cooktopKnobProgress?: number[] | undefined;
746
+ cooktopShowGrate?: boolean | undefined;
747
+ height?: number | undefined;
748
+ } | {
749
+ type: "cooktop-induction";
750
+ id: string;
751
+ cooktopLayout?: "induction-2zone" | "induction-4zone" | undefined;
752
+ cooktopBurnersOn?: boolean | undefined;
753
+ cooktopActiveBurners?: number[] | undefined;
754
+ cooktopKnobProgress?: number[] | undefined;
755
+ cooktopShowGrate?: boolean | undefined;
756
+ height?: number | undefined;
757
+ } | {
758
+ type: "pull-out-pantry";
759
+ id: string;
760
+ shelfCount?: number | undefined;
761
+ pantryRackStyle?: "glass" | "wire" | "tray" | undefined;
762
+ height?: number | undefined;
763
+ } | {
764
+ type: "fridge-single";
765
+ id: string;
766
+ height?: number | undefined;
767
+ } | {
768
+ type: "fridge-double";
769
+ id: string;
770
+ height?: number | undefined;
771
+ } | {
772
+ type: "fridge-top-freezer";
773
+ id: string;
774
+ height?: number | undefined;
775
+ } | {
776
+ type: "fridge-bottom-freezer";
777
+ id: string;
778
+ height?: number | undefined;
779
+ } | {
780
+ type: "hood-pyramid";
781
+ id: string;
782
+ height?: number | undefined;
783
+ } | {
784
+ type: "hood-curved-glass";
785
+ id: string;
786
+ height?: number | undefined;
787
+ })[] | undefined;
788
+ } | {
789
+ object: "node";
790
+ position: [number, number, number];
791
+ id: `cabinet-module_${string}`;
792
+ parentId: string | null;
793
+ visible: boolean;
794
+ metadata: Record<string, unknown>;
795
+ rotation: number;
796
+ children: (`cabinet_${string}` | `cabinet-module_${string}`)[];
797
+ width: number;
798
+ depth: number;
799
+ operationState: number;
800
+ carcassHeight: number;
801
+ plinthHeight: number;
802
+ toeKickDepth: number;
803
+ boardThickness: number;
804
+ countertopThickness: number;
805
+ countertopOverhang: number;
806
+ countertopBackOverhang: number;
807
+ withFinishedBack: boolean;
808
+ frontThickness: number;
809
+ frontGap: number;
810
+ frontStyle: "slab" | "shaker" | "raised-arch";
811
+ panelReady: boolean;
812
+ handleStyle: "none" | "bar" | "cutout" | "hole" | "knob";
813
+ handlePosition: "top" | "auto" | "center";
814
+ frontOverlay: "full" | "inset";
815
+ withBottomPanel: boolean;
816
+ showPlinth: boolean;
817
+ withCountertop: boolean;
818
+ cabinetType: "base" | "tall";
819
+ moduleKind: "standard" | "corner-filler";
820
+ topFinish: "trim" | "none" | "top-cabinet";
821
+ topFinishHeight: number;
822
+ topFinishDepth: number;
823
+ type: "cabinet-module";
824
+ name?: string | undefined;
825
+ camera?: {
826
+ position: [number, number, number];
827
+ target: [number, number, number];
828
+ mode: "perspective" | "orthographic";
829
+ fov?: number | undefined;
830
+ zoom?: number | undefined;
831
+ } | undefined;
832
+ supportSlabId?: string | undefined;
833
+ slots?: Record<string, string> | undefined;
834
+ material?: {
835
+ id?: string | undefined;
836
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
837
+ properties?: {
838
+ color: string;
839
+ roughness: number;
840
+ metalness: number;
841
+ opacity: number;
842
+ transparent: boolean;
843
+ side: "front" | "back" | "double";
844
+ } | undefined;
845
+ texture?: {
846
+ url: string;
847
+ repeat?: [number, number] | undefined;
848
+ scale?: number | undefined;
849
+ } | undefined;
850
+ } | undefined;
851
+ materialPreset?: string | undefined;
852
+ stack?: ({
853
+ type: "shelf";
854
+ id: string;
855
+ shelfCount?: number | undefined;
856
+ height?: number | undefined;
857
+ } | {
858
+ type: "drawer";
859
+ id: string;
860
+ drawerCount?: number | undefined;
861
+ height?: number | undefined;
862
+ } | {
863
+ type: "door";
864
+ id: string;
865
+ doorType?: "glass" | "double" | "single-left" | "single-right" | undefined;
866
+ shelfCount?: number | undefined;
867
+ height?: number | undefined;
868
+ } | {
869
+ type: "sink";
870
+ id: string;
871
+ sinkLayout?: "double" | "single" | "double-offset" | undefined;
872
+ height?: number | undefined;
873
+ } | {
874
+ type: "oven";
875
+ id: string;
876
+ height?: number | undefined;
877
+ } | {
878
+ type: "microwave";
879
+ id: string;
880
+ height?: number | undefined;
881
+ } | {
882
+ type: "dishwasher";
883
+ id: string;
884
+ height?: number | undefined;
885
+ } | {
886
+ type: "cooktop-gas";
887
+ id: string;
888
+ cooktopLayout?: "gas-2burner" | "gas-4burner" | "gas-5burner-wok" | "gas-6burner" | undefined;
889
+ cooktopBurnersOn?: boolean | undefined;
890
+ cooktopActiveBurners?: number[] | undefined;
891
+ cooktopKnobProgress?: number[] | undefined;
892
+ cooktopShowGrate?: boolean | undefined;
893
+ height?: number | undefined;
894
+ } | {
895
+ type: "cooktop-induction";
896
+ id: string;
897
+ cooktopLayout?: "induction-2zone" | "induction-4zone" | undefined;
898
+ cooktopBurnersOn?: boolean | undefined;
899
+ cooktopActiveBurners?: number[] | undefined;
900
+ cooktopKnobProgress?: number[] | undefined;
901
+ cooktopShowGrate?: boolean | undefined;
902
+ height?: number | undefined;
903
+ } | {
904
+ type: "pull-out-pantry";
905
+ id: string;
906
+ shelfCount?: number | undefined;
907
+ pantryRackStyle?: "glass" | "wire" | "tray" | undefined;
908
+ height?: number | undefined;
909
+ } | {
910
+ type: "fridge-single";
911
+ id: string;
912
+ height?: number | undefined;
913
+ } | {
914
+ type: "fridge-double";
915
+ id: string;
916
+ height?: number | undefined;
917
+ } | {
918
+ type: "fridge-top-freezer";
919
+ id: string;
920
+ height?: number | undefined;
921
+ } | {
922
+ type: "fridge-bottom-freezer";
923
+ id: string;
924
+ height?: number | undefined;
925
+ } | {
926
+ type: "hood-pyramid";
927
+ id: string;
928
+ height?: number | undefined;
929
+ } | {
930
+ type: "hood-curved-glass";
931
+ id: string;
932
+ height?: number | undefined;
933
+ })[] | undefined;
934
+ openSide?: "right" | "left" | undefined;
935
+ cornerShelf?: boolean | undefined;
936
+ } | {
937
+ object: "node";
938
+ position: [number, number, number];
939
+ id: `item_${string}`;
940
+ parentId: string | null;
941
+ visible: boolean;
942
+ metadata: Record<string, unknown>;
943
+ rotation: [number, number, number];
944
+ scale: [number, number, number];
945
+ children: `item_${string}`[];
946
+ asset: {
947
+ id: string;
948
+ category: string;
949
+ name: string;
950
+ thumbnail: string;
951
+ source: "library" | "community" | "mine";
952
+ src: string;
953
+ dimensions: [number, number, number];
954
+ offset: [number, number, number];
955
+ rotation: [number, number, number];
956
+ scale: [number, number, number];
957
+ floorPlanUrl?: string | undefined;
958
+ isDraft?: boolean | undefined;
959
+ attachTo?: "wall" | "wall-side" | "ceiling" | undefined;
960
+ recessed?: boolean | undefined;
961
+ tags?: string[] | undefined;
962
+ functionTags?: string[] | undefined;
963
+ surface?: {
964
+ height: number;
965
+ } | undefined;
966
+ interactive?: {
967
+ controls: ({
968
+ kind: "toggle";
969
+ label?: string | undefined;
970
+ default?: boolean | undefined;
971
+ } | {
972
+ kind: "slider";
973
+ label: string;
974
+ min: number;
975
+ max: number;
976
+ step: number;
977
+ displayMode: "slider" | "stepper" | "dial";
978
+ unit?: string | undefined;
979
+ default?: number | undefined;
980
+ } | {
981
+ kind: "temperature";
982
+ label: string;
983
+ min: number;
984
+ max: number;
985
+ unit: "C" | "F";
986
+ default?: number | undefined;
987
+ })[];
988
+ effects: ({
989
+ kind: "animation";
990
+ clips: {
991
+ on?: string | undefined;
992
+ off?: string | undefined;
993
+ loop?: string | undefined;
994
+ };
995
+ } | {
996
+ kind: "light";
997
+ color: string;
998
+ intensityRange: [number, number];
999
+ offset: [number, number, number];
1000
+ distance?: number | undefined;
1001
+ })[];
1002
+ } | undefined;
1003
+ };
1004
+ type: "item";
1005
+ name?: string | undefined;
1006
+ camera?: {
1007
+ position: [number, number, number];
1008
+ target: [number, number, number];
1009
+ mode: "perspective" | "orthographic";
1010
+ fov?: number | undefined;
1011
+ zoom?: number | undefined;
1012
+ } | undefined;
1013
+ side?: "front" | "back" | undefined;
1014
+ wallId?: string | undefined;
1015
+ wallT?: number | undefined;
1016
+ roofSegmentId?: string | undefined;
1017
+ roofFace?: "front" | "back" | "right" | "left" | undefined;
1018
+ blockFaceId?: string | undefined;
1019
+ supportSlabId?: string | undefined;
1020
+ collectionIds?: `collection_${string}`[] | undefined;
1021
+ slots?: Record<string, string> | undefined;
1022
+ } | {
1023
+ object: "node";
1024
+ id: `zone_${string}`;
1025
+ name: string;
1026
+ parentId: string | null;
1027
+ visible: boolean;
1028
+ metadata: Record<string, unknown>;
1029
+ color: string;
1030
+ polygon: [number, number][];
1031
+ autoFromWalls: boolean;
1032
+ boundaryWallIds: `wall_${string}`[];
1033
+ spaceRole: "generic" | "room";
1034
+ roomNumber: string;
1035
+ enclosureStatus: "auto" | "open" | "enclosed";
1036
+ floorFinish: string;
1037
+ wallFinish: string;
1038
+ ceilingFinish: string;
1039
+ ceilingHeight: number;
1040
+ occupancy: string;
1041
+ clearDimensionPolicy: "none" | "inside-faces" | "finish-faces";
1042
+ type: "zone";
1043
+ camera?: {
1044
+ position: [number, number, number];
1045
+ target: [number, number, number];
1046
+ mode: "perspective" | "orthographic";
1047
+ fov?: number | undefined;
1048
+ zoom?: number | undefined;
1049
+ } | undefined;
1050
+ } | {
1051
+ object: "node";
1052
+ id: `slab_${string}`;
1053
+ parentId: string | null;
1054
+ visible: boolean;
1055
+ metadata: Record<string, unknown>;
1056
+ recessed: boolean;
1057
+ polygon: [number, number][];
1058
+ holes: [number, number][][];
1059
+ holeMetadata: {
1060
+ source: "stair" | "elevator" | "manual";
1061
+ stairId?: string | undefined;
1062
+ elevatorId?: string | undefined;
1063
+ }[];
1064
+ autoFromWalls: boolean;
1065
+ elevation: number;
1066
+ thickness: number;
1067
+ type: "slab";
1068
+ name?: string | undefined;
1069
+ camera?: {
1070
+ position: [number, number, number];
1071
+ target: [number, number, number];
1072
+ mode: "perspective" | "orthographic";
1073
+ fov?: number | undefined;
1074
+ zoom?: number | undefined;
1075
+ } | undefined;
1076
+ slots?: Record<string, string> | undefined;
1077
+ material?: {
1078
+ id?: string | undefined;
1079
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1080
+ properties?: {
1081
+ color: string;
1082
+ roughness: number;
1083
+ metalness: number;
1084
+ opacity: number;
1085
+ transparent: boolean;
1086
+ side: "front" | "back" | "double";
1087
+ } | undefined;
1088
+ texture?: {
1089
+ url: string;
1090
+ repeat?: [number, number] | undefined;
1091
+ scale?: number | undefined;
1092
+ } | undefined;
1093
+ } | undefined;
1094
+ materialPreset?: string | undefined;
1095
+ recessedRimElevation?: number | undefined;
1096
+ fillToTerrain?: boolean | undefined;
1097
+ } | {
1098
+ object: "node";
1099
+ id: `ceiling_${string}`;
1100
+ parentId: string | null;
1101
+ visible: boolean;
1102
+ metadata: Record<string, unknown>;
1103
+ children: `item_${string}`[];
1104
+ polygon: [number, number][];
1105
+ holes: [number, number][][];
1106
+ holeMetadata: {
1107
+ source: "stair" | "elevator" | "manual";
1108
+ stairId?: string | undefined;
1109
+ elevatorId?: string | undefined;
1110
+ }[];
1111
+ autoFromWalls: boolean;
1112
+ type: "ceiling";
1113
+ name?: string | undefined;
1114
+ camera?: {
1115
+ position: [number, number, number];
1116
+ target: [number, number, number];
1117
+ mode: "perspective" | "orthographic";
1118
+ fov?: number | undefined;
1119
+ zoom?: number | undefined;
1120
+ } | undefined;
1121
+ height?: number | undefined;
1122
+ slots?: Record<string, string> | undefined;
1123
+ material?: {
1124
+ id?: string | undefined;
1125
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1126
+ properties?: {
1127
+ color: string;
1128
+ roughness: number;
1129
+ metalness: number;
1130
+ opacity: number;
1131
+ transparent: boolean;
1132
+ side: "front" | "back" | "double";
1133
+ } | undefined;
1134
+ texture?: {
1135
+ url: string;
1136
+ repeat?: [number, number] | undefined;
1137
+ scale?: number | undefined;
1138
+ } | undefined;
1139
+ } | undefined;
1140
+ materialPreset?: string | undefined;
1141
+ } | {
1142
+ object: "node";
1143
+ position: [number, number, number];
1144
+ id: `roof_${string}`;
1145
+ parentId: string | null;
1146
+ visible: boolean;
1147
+ metadata: Record<string, unknown>;
1148
+ rotation: number;
1149
+ children: `rseg_${string}`[];
1150
+ support: {
1151
+ kind: "level";
1152
+ } | {
1153
+ kind: "walls";
1154
+ } | {
1155
+ kind: "roof";
1156
+ roofSegmentId: `rseg_${string}`;
1157
+ localPosition: [number, number];
1158
+ curbHeight: number;
1159
+ };
1160
+ type: "roof";
1161
+ name?: string | undefined;
1162
+ camera?: {
1163
+ position: [number, number, number];
1164
+ target: [number, number, number];
1165
+ mode: "perspective" | "orthographic";
1166
+ fov?: number | undefined;
1167
+ zoom?: number | undefined;
1168
+ } | undefined;
1169
+ material?: {
1170
+ id?: string | undefined;
1171
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1172
+ properties?: {
1173
+ color: string;
1174
+ roughness: number;
1175
+ metalness: number;
1176
+ opacity: number;
1177
+ transparent: boolean;
1178
+ side: "front" | "back" | "double";
1179
+ } | undefined;
1180
+ texture?: {
1181
+ url: string;
1182
+ repeat?: [number, number] | undefined;
1183
+ scale?: number | undefined;
1184
+ } | undefined;
1185
+ } | undefined;
1186
+ materialPreset?: string | undefined;
1187
+ topMaterial?: {
1188
+ id?: string | undefined;
1189
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1190
+ properties?: {
1191
+ color: string;
1192
+ roughness: number;
1193
+ metalness: number;
1194
+ opacity: number;
1195
+ transparent: boolean;
1196
+ side: "front" | "back" | "double";
1197
+ } | undefined;
1198
+ texture?: {
1199
+ url: string;
1200
+ repeat?: [number, number] | undefined;
1201
+ scale?: number | undefined;
1202
+ } | undefined;
1203
+ } | undefined;
1204
+ topMaterialPreset?: string | undefined;
1205
+ edgeMaterial?: {
1206
+ id?: string | undefined;
1207
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1208
+ properties?: {
1209
+ color: string;
1210
+ roughness: number;
1211
+ metalness: number;
1212
+ opacity: number;
1213
+ transparent: boolean;
1214
+ side: "front" | "back" | "double";
1215
+ } | undefined;
1216
+ texture?: {
1217
+ url: string;
1218
+ repeat?: [number, number] | undefined;
1219
+ scale?: number | undefined;
1220
+ } | undefined;
1221
+ } | undefined;
1222
+ edgeMaterialPreset?: string | undefined;
1223
+ wallMaterial?: {
1224
+ id?: string | undefined;
1225
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1226
+ properties?: {
1227
+ color: string;
1228
+ roughness: number;
1229
+ metalness: number;
1230
+ opacity: number;
1231
+ transparent: boolean;
1232
+ side: "front" | "back" | "double";
1233
+ } | undefined;
1234
+ texture?: {
1235
+ url: string;
1236
+ repeat?: [number, number] | undefined;
1237
+ scale?: number | undefined;
1238
+ } | undefined;
1239
+ } | undefined;
1240
+ wallMaterialPreset?: string | undefined;
1241
+ } | {
1242
+ object: "node";
1243
+ position: [number, number, number];
1244
+ id: `rseg_${string}`;
1245
+ parentId: string | null;
1246
+ visible: boolean;
1247
+ metadata: Record<string, unknown>;
1248
+ rotation: number;
1249
+ children: string[];
1250
+ trim: {
1251
+ left: number;
1252
+ right: number;
1253
+ front: number;
1254
+ back: number;
1255
+ frontLeft: number;
1256
+ frontRight: number;
1257
+ backLeft: number;
1258
+ backRight: number;
1259
+ frontLeftX: number;
1260
+ frontLeftZ: number;
1261
+ frontRightX: number;
1262
+ frontRightZ: number;
1263
+ backLeftX: number;
1264
+ backLeftZ: number;
1265
+ backRightX: number;
1266
+ backRightZ: number;
1267
+ };
1268
+ width: number;
1269
+ depth: number;
1270
+ roofType: "flat" | "hip" | "gable" | "shed" | "gambrel" | "dutch" | "mansard" | "conical";
1271
+ wallHeight: number;
1272
+ pitch: number;
1273
+ wallThickness: number;
1274
+ deckThickness: number;
1275
+ overhang: number;
1276
+ shingleThickness: number;
1277
+ managedByParent: boolean;
1278
+ wallShell: "auto" | "include" | "omit";
1279
+ shedInsetEndPanels: boolean;
1280
+ gambrelLowerWidthRatio: number;
1281
+ gambrelLowerHeightRatio: number;
1282
+ mansardSteepWidthRatio: number;
1283
+ mansardSteepHeightRatio: number;
1284
+ dutchHipWidthRatio: number;
1285
+ dutchHipHeightRatio: number;
1286
+ dutchWaistLengthRatio: number;
1287
+ dutchGabletRake: number;
1288
+ dutchTopRakeThickness: number;
1289
+ type: "roof-segment";
1290
+ name?: string | undefined;
1291
+ camera?: {
1292
+ position: [number, number, number];
1293
+ target: [number, number, number];
1294
+ mode: "perspective" | "orthographic";
1295
+ fov?: number | undefined;
1296
+ zoom?: number | undefined;
1297
+ } | undefined;
1298
+ material?: {
1299
+ id?: string | undefined;
1300
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1301
+ properties?: {
1302
+ color: string;
1303
+ roughness: number;
1304
+ metalness: number;
1305
+ opacity: number;
1306
+ transparent: boolean;
1307
+ side: "front" | "back" | "double";
1308
+ } | undefined;
1309
+ texture?: {
1310
+ url: string;
1311
+ repeat?: [number, number] | undefined;
1312
+ scale?: number | undefined;
1313
+ } | undefined;
1314
+ } | undefined;
1315
+ materialPreset?: string | undefined;
1316
+ topMaterial?: {
1317
+ id?: string | undefined;
1318
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1319
+ properties?: {
1320
+ color: string;
1321
+ roughness: number;
1322
+ metalness: number;
1323
+ opacity: number;
1324
+ transparent: boolean;
1325
+ side: "front" | "back" | "double";
1326
+ } | undefined;
1327
+ texture?: {
1328
+ url: string;
1329
+ repeat?: [number, number] | undefined;
1330
+ scale?: number | undefined;
1331
+ } | undefined;
1332
+ } | undefined;
1333
+ topMaterialPreset?: string | undefined;
1334
+ edgeMaterial?: {
1335
+ id?: string | undefined;
1336
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1337
+ properties?: {
1338
+ color: string;
1339
+ roughness: number;
1340
+ metalness: number;
1341
+ opacity: number;
1342
+ transparent: boolean;
1343
+ side: "front" | "back" | "double";
1344
+ } | undefined;
1345
+ texture?: {
1346
+ url: string;
1347
+ repeat?: [number, number] | undefined;
1348
+ scale?: number | undefined;
1349
+ } | undefined;
1350
+ } | undefined;
1351
+ edgeMaterialPreset?: string | undefined;
1352
+ wallMaterial?: {
1353
+ id?: string | undefined;
1354
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1355
+ properties?: {
1356
+ color: string;
1357
+ roughness: number;
1358
+ metalness: number;
1359
+ opacity: number;
1360
+ transparent: boolean;
1361
+ side: "front" | "back" | "double";
1362
+ } | undefined;
1363
+ texture?: {
1364
+ url: string;
1365
+ repeat?: [number, number] | undefined;
1366
+ scale?: number | undefined;
1367
+ } | undefined;
1368
+ } | undefined;
1369
+ wallMaterialPreset?: string | undefined;
1370
+ conicalStartAngle?: number | undefined;
1371
+ conicalSweepAngle?: number | undefined;
1372
+ conicalFullCircle?: boolean | undefined;
1373
+ arc?: {
1374
+ centerX: number;
1375
+ centerZ: number;
1376
+ radius: number;
1377
+ } | undefined;
1378
+ shedSideInfillSpan?: number | undefined;
1379
+ shedSideInfillMinX?: number | undefined;
1380
+ shedSideInfillMaxX?: number | undefined;
1381
+ shedFootprintPieces?: [number, number][][] | undefined;
1382
+ shedOpenEndSides?: ("right" | "left")[] | undefined;
1383
+ shedJointFrame?: {
1384
+ position: [number, number, number];
1385
+ rotation: number;
1386
+ } | undefined;
1387
+ shedJointOwnerId?: string | undefined;
1388
+ shedJointNeighborIds?: string[] | undefined;
1389
+ shedJointScopeId?: string | undefined;
1390
+ } | {
1391
+ object: "node";
1392
+ position: [number, number, number];
1393
+ id: `shelf_${string}`;
1394
+ parentId: string | null;
1395
+ visible: boolean;
1396
+ metadata: Record<string, unknown>;
1397
+ rotation: [number, number, number];
1398
+ height: number;
1399
+ children: `item_${string}`[];
1400
+ width: number;
1401
+ depth: number;
1402
+ style: "wall-shelf" | "bookshelf" | "open-rack" | "cubby";
1403
+ rows: number;
1404
+ thickness: number;
1405
+ columns: number;
1406
+ withBack: boolean;
1407
+ withSides: boolean;
1408
+ withBottom: boolean;
1409
+ bracketStyle: "hidden" | "minimal" | "industrial";
1410
+ type: "shelf";
1411
+ name?: string | undefined;
1412
+ camera?: {
1413
+ position: [number, number, number];
1414
+ target: [number, number, number];
1415
+ mode: "perspective" | "orthographic";
1416
+ fov?: number | undefined;
1417
+ zoom?: number | undefined;
1418
+ } | undefined;
1419
+ supportSlabId?: string | undefined;
1420
+ slots?: Record<string, string> | undefined;
1421
+ material?: {
1422
+ id?: string | undefined;
1423
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1424
+ properties?: {
1425
+ color: string;
1426
+ roughness: number;
1427
+ metalness: number;
1428
+ opacity: number;
1429
+ transparent: boolean;
1430
+ side: "front" | "back" | "double";
1431
+ } | undefined;
1432
+ texture?: {
1433
+ url: string;
1434
+ repeat?: [number, number] | undefined;
1435
+ scale?: number | undefined;
1436
+ } | undefined;
1437
+ } | undefined;
1438
+ materialPreset?: string | undefined;
1439
+ } | {
1440
+ object: "node";
1441
+ position: [number, number, number];
1442
+ id: `stair_${string}`;
1443
+ parentId: string | null;
1444
+ visible: boolean;
1445
+ metadata: Record<string, unknown>;
1446
+ rotation: number;
1447
+ children: `sseg_${string}`[];
1448
+ width: number;
1449
+ fromLevelId: string | null;
1450
+ toLevelId: string | null;
1451
+ thickness: number;
1452
+ stairType: "straight" | "spiral" | "curved";
1453
+ slabOpeningMode: "none" | "destination";
1454
+ openingOffset: number;
1455
+ stepCount: number;
1456
+ fillToFloor: boolean;
1457
+ innerRadius: number;
1458
+ sweepAngle: number;
1459
+ topLandingMode: "none" | "integrated";
1460
+ topLandingDepth: number;
1461
+ showCenterColumn: boolean;
1462
+ showStepSupports: boolean;
1463
+ railingMode: "right" | "left" | "none" | "both";
1464
+ railingHeight: number;
1465
+ type: "stair";
1466
+ name?: string | undefined;
1467
+ camera?: {
1468
+ position: [number, number, number];
1469
+ target: [number, number, number];
1470
+ mode: "perspective" | "orthographic";
1471
+ fov?: number | undefined;
1472
+ zoom?: number | undefined;
1473
+ } | undefined;
1474
+ supportSlabId?: string | undefined;
1475
+ slots?: Record<string, string> | undefined;
1476
+ material?: {
1477
+ id?: string | undefined;
1478
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1479
+ properties?: {
1480
+ color: string;
1481
+ roughness: number;
1482
+ metalness: number;
1483
+ opacity: number;
1484
+ transparent: boolean;
1485
+ side: "front" | "back" | "double";
1486
+ } | undefined;
1487
+ texture?: {
1488
+ url: string;
1489
+ repeat?: [number, number] | undefined;
1490
+ scale?: number | undefined;
1491
+ } | undefined;
1492
+ } | undefined;
1493
+ materialPreset?: string | undefined;
1494
+ railingMaterial?: {
1495
+ id?: string | undefined;
1496
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1497
+ properties?: {
1498
+ color: string;
1499
+ roughness: number;
1500
+ metalness: number;
1501
+ opacity: number;
1502
+ transparent: boolean;
1503
+ side: "front" | "back" | "double";
1504
+ } | undefined;
1505
+ texture?: {
1506
+ url: string;
1507
+ repeat?: [number, number] | undefined;
1508
+ scale?: number | undefined;
1509
+ } | undefined;
1510
+ } | undefined;
1511
+ railingMaterialPreset?: string | undefined;
1512
+ treadMaterial?: {
1513
+ id?: string | undefined;
1514
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1515
+ properties?: {
1516
+ color: string;
1517
+ roughness: number;
1518
+ metalness: number;
1519
+ opacity: number;
1520
+ transparent: boolean;
1521
+ side: "front" | "back" | "double";
1522
+ } | undefined;
1523
+ texture?: {
1524
+ url: string;
1525
+ repeat?: [number, number] | undefined;
1526
+ scale?: number | undefined;
1527
+ } | undefined;
1528
+ } | undefined;
1529
+ treadMaterialPreset?: string | undefined;
1530
+ sideMaterial?: {
1531
+ id?: string | undefined;
1532
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1533
+ properties?: {
1534
+ color: string;
1535
+ roughness: number;
1536
+ metalness: number;
1537
+ opacity: number;
1538
+ transparent: boolean;
1539
+ side: "front" | "back" | "double";
1540
+ } | undefined;
1541
+ texture?: {
1542
+ url: string;
1543
+ repeat?: [number, number] | undefined;
1544
+ scale?: number | undefined;
1545
+ } | undefined;
1546
+ } | undefined;
1547
+ sideMaterialPreset?: string | undefined;
1548
+ deckSlabId?: string | undefined;
1549
+ totalRise?: number | undefined;
1550
+ } | {
1551
+ object: "node";
1552
+ length: number;
1553
+ position: [number, number, number];
1554
+ id: `sseg_${string}`;
1555
+ parentId: string | null;
1556
+ visible: boolean;
1557
+ metadata: Record<string, unknown>;
1558
+ rotation: number;
1559
+ height: number;
1560
+ width: number;
1561
+ thickness: number;
1562
+ stepCount: number;
1563
+ fillToFloor: boolean;
1564
+ segmentType: "stair" | "landing";
1565
+ attachmentSide: "front" | "right" | "left";
1566
+ type: "stair-segment";
1567
+ name?: string | undefined;
1568
+ camera?: {
1569
+ position: [number, number, number];
1570
+ target: [number, number, number];
1571
+ mode: "perspective" | "orthographic";
1572
+ fov?: number | undefined;
1573
+ zoom?: number | undefined;
1574
+ } | undefined;
1575
+ material?: {
1576
+ id?: string | undefined;
1577
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1578
+ properties?: {
1579
+ color: string;
1580
+ roughness: number;
1581
+ metalness: number;
1582
+ opacity: number;
1583
+ transparent: boolean;
1584
+ side: "front" | "back" | "double";
1585
+ } | undefined;
1586
+ texture?: {
1587
+ url: string;
1588
+ repeat?: [number, number] | undefined;
1589
+ scale?: number | undefined;
1590
+ } | undefined;
1591
+ } | undefined;
1592
+ materialPreset?: string | undefined;
1593
+ } | {
1594
+ object: "node";
1595
+ position: [number, number, number];
1596
+ id: `scan_${string}`;
1597
+ parentId: string | null;
1598
+ visible: boolean;
1599
+ metadata: Record<string, unknown>;
1600
+ rotation: [number, number, number];
1601
+ scale: number;
1602
+ url: string | null;
1603
+ opacity: number;
1604
+ captureSession: {
1605
+ sessionId: string;
1606
+ schemaVersion?: number | undefined;
1607
+ revisionId?: string | undefined;
1608
+ manifestUrl?: string | undefined;
1609
+ } | null;
1610
+ layers: Record<string, boolean>;
1611
+ type: "scan";
1612
+ name?: string | undefined;
1613
+ camera?: {
1614
+ position: [number, number, number];
1615
+ target: [number, number, number];
1616
+ mode: "perspective" | "orthographic";
1617
+ fov?: number | undefined;
1618
+ zoom?: number | undefined;
1619
+ } | undefined;
1620
+ } | {
1621
+ object: "node";
1622
+ position: [number, number, number];
1623
+ id: `guide_${string}`;
1624
+ parentId: string | null;
1625
+ visible: boolean;
1626
+ metadata: Record<string, unknown>;
1627
+ rotation: [number, number, number];
1628
+ scale: number;
1629
+ url: string;
1630
+ opacity: number;
1631
+ scaleReference: {
1632
+ start: [number, number];
1633
+ end: [number, number];
1634
+ realLengthMeters: number;
1635
+ measuredLengthUnits: number;
1636
+ metersPerUnit: number;
1637
+ label: string;
1638
+ } | null;
1639
+ type: "guide";
1640
+ name?: string | undefined;
1641
+ camera?: {
1642
+ position: [number, number, number];
1643
+ target: [number, number, number];
1644
+ mode: "perspective" | "orthographic";
1645
+ fov?: number | undefined;
1646
+ zoom?: number | undefined;
1647
+ } | undefined;
1648
+ } | {
1649
+ object: "node";
1650
+ id: `measurement_${string}`;
1651
+ parentId: string | null;
1652
+ visible: boolean;
1653
+ metadata: Record<string, unknown>;
1654
+ measurement: {
1655
+ kind: "distance";
1656
+ points: [[number, number, number] | {
1657
+ kind: "feature";
1658
+ reference: {
1659
+ nodeId: string;
1660
+ featureId: string;
1661
+ parameters?: Record<string, string | number | boolean> | undefined;
1662
+ };
1663
+ fallback: [number, number, number];
1664
+ }, [number, number, number] | {
1665
+ kind: "feature";
1666
+ reference: {
1667
+ nodeId: string;
1668
+ featureId: string;
1669
+ parameters?: Record<string, string | number | boolean> | undefined;
1670
+ };
1671
+ fallback: [number, number, number];
1672
+ }];
1673
+ } | {
1674
+ kind: "angle";
1675
+ points: [[number, number, number] | {
1676
+ kind: "feature";
1677
+ reference: {
1678
+ nodeId: string;
1679
+ featureId: string;
1680
+ parameters?: Record<string, string | number | boolean> | undefined;
1681
+ };
1682
+ fallback: [number, number, number];
1683
+ }, [number, number, number] | {
1684
+ kind: "feature";
1685
+ reference: {
1686
+ nodeId: string;
1687
+ featureId: string;
1688
+ parameters?: Record<string, string | number | boolean> | undefined;
1689
+ };
1690
+ fallback: [number, number, number];
1691
+ }, [number, number, number] | {
1692
+ kind: "feature";
1693
+ reference: {
1694
+ nodeId: string;
1695
+ featureId: string;
1696
+ parameters?: Record<string, string | number | boolean> | undefined;
1697
+ };
1698
+ fallback: [number, number, number];
1699
+ }];
1700
+ } | {
1701
+ kind: "area";
1702
+ base: ([number, number, number] | {
1703
+ kind: "feature";
1704
+ reference: {
1705
+ nodeId: string;
1706
+ featureId: string;
1707
+ parameters?: Record<string, string | number | boolean> | undefined;
1708
+ };
1709
+ fallback: [number, number, number];
1710
+ })[];
1711
+ } | {
1712
+ kind: "perimeter";
1713
+ base: ([number, number, number] | {
1714
+ kind: "feature";
1715
+ reference: {
1716
+ nodeId: string;
1717
+ featureId: string;
1718
+ parameters?: Record<string, string | number | boolean> | undefined;
1719
+ };
1720
+ fallback: [number, number, number];
1721
+ })[];
1722
+ } | {
1723
+ kind: "volume";
1724
+ base: ([number, number, number] | {
1725
+ kind: "feature";
1726
+ reference: {
1727
+ nodeId: string;
1728
+ featureId: string;
1729
+ parameters?: Record<string, string | number | boolean> | undefined;
1730
+ };
1731
+ fallback: [number, number, number];
1732
+ })[];
1733
+ extrusion: [number, number, number];
1734
+ };
1735
+ type: "measurement";
1736
+ name?: string | undefined;
1737
+ camera?: {
1738
+ position: [number, number, number];
1739
+ target: [number, number, number];
1740
+ mode: "perspective" | "orthographic";
1741
+ fov?: number | undefined;
1742
+ zoom?: number | undefined;
1743
+ } | undefined;
1744
+ } | {
1745
+ object: "node";
1746
+ position: [number, number, number];
1747
+ id: `spawn_${string}`;
1748
+ parentId: string | null;
1749
+ visible: boolean;
1750
+ metadata: Record<string, unknown>;
1751
+ rotation: number;
1752
+ type: "spawn";
1753
+ name?: string | undefined;
1754
+ camera?: {
1755
+ position: [number, number, number];
1756
+ target: [number, number, number];
1757
+ mode: "perspective" | "orthographic";
1758
+ fov?: number | undefined;
1759
+ zoom?: number | undefined;
1760
+ } | undefined;
1761
+ supportSlabId?: string | undefined;
1762
+ } | {
1763
+ object: "node";
1764
+ position: [number, number, number];
1765
+ id: `window_${string}`;
1766
+ parentId: string | null;
1767
+ visible: boolean;
1768
+ metadata: Record<string, unknown>;
1769
+ rotation: [number, number, number];
1770
+ height: number;
1771
+ width: number;
1772
+ constructionType: "framed" | "masonry";
1773
+ dimensionReference: "nominal" | "rough-opening" | "masonry-opening" | "finish-opening";
1774
+ operationState: number;
1775
+ openingKind: "window" | "opening";
1776
+ openingShape: "rectangle" | "rounded" | "arch";
1777
+ openingRadiusMode: "all" | "individual";
1778
+ cornerRadius: number;
1779
+ archHeight: number;
1780
+ openingRevealRadius: number;
1781
+ frameThickness: number;
1782
+ frameDepth: number;
1783
+ hingesSide: "right" | "left";
1784
+ columnRatios: number[];
1785
+ windowType: "fixed" | "sliding" | "casement" | "awning" | "hopper" | "single-hung" | "double-hung" | "bay" | "bow" | "louvered";
1786
+ awningDirection: "up" | "down";
1787
+ casementStyle: "french" | "single";
1788
+ openingCornerRadii: [number, number, number, number];
1789
+ rowRatios: number[];
1790
+ columnDividerThickness: number;
1791
+ rowDividerThickness: number;
1792
+ sill: boolean;
1793
+ sillDepth: number;
1794
+ sillThickness: number;
1795
+ type: "window";
1796
+ name?: string | undefined;
1797
+ camera?: {
1798
+ position: [number, number, number];
1799
+ target: [number, number, number];
1800
+ mode: "perspective" | "orthographic";
1801
+ fov?: number | undefined;
1802
+ zoom?: number | undefined;
1803
+ } | undefined;
1804
+ side?: "front" | "back" | undefined;
1805
+ wallId?: string | undefined;
1806
+ roofSegmentId?: string | undefined;
1807
+ roofFace?: "front" | "back" | "right" | "left" | undefined;
1808
+ slots?: Record<string, string> | undefined;
1809
+ material?: {
1810
+ id?: string | undefined;
1811
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1812
+ properties?: {
1813
+ color: string;
1814
+ roughness: number;
1815
+ metalness: number;
1816
+ opacity: number;
1817
+ transparent: boolean;
1818
+ side: "front" | "back" | "double";
1819
+ } | undefined;
1820
+ texture?: {
1821
+ url: string;
1822
+ repeat?: [number, number] | undefined;
1823
+ scale?: number | undefined;
1824
+ } | undefined;
1825
+ } | undefined;
1826
+ mark?: string | undefined;
1827
+ roughOpeningWidth?: number | undefined;
1828
+ roughOpeningHeight?: number | undefined;
1829
+ masonryOpeningWidth?: number | undefined;
1830
+ masonryOpeningHeight?: number | undefined;
1831
+ finishOpeningWidth?: number | undefined;
1832
+ finishOpeningHeight?: number | undefined;
1833
+ dormerId?: string | undefined;
1834
+ dormerFace?: "front" | "back" | "right" | "left" | undefined;
1835
+ } | {
1836
+ object: "node";
1837
+ position: [number, number, number];
1838
+ id: `door_${string}`;
1839
+ parentId: string | null;
1840
+ visible: boolean;
1841
+ metadata: Record<string, unknown>;
1842
+ rotation: [number, number, number];
1843
+ height: number;
1844
+ width: number;
1845
+ leafCount: 4 | 1 | 2 | 3;
1846
+ constructionType: "framed" | "masonry";
1847
+ dimensionReference: "nominal" | "rough-opening" | "masonry-opening" | "finish-opening";
1848
+ doorCategory: "interior" | "garage";
1849
+ doorType: "double" | "hinged" | "french" | "folding" | "pocket" | "barn" | "sliding" | "garage-sectional" | "garage-rollup" | "garage-tiltup";
1850
+ operationState: number;
1851
+ slideDirection: "right" | "left";
1852
+ trackStyle: "visible" | "none" | "pocket" | "overhead";
1853
+ garagePanelCount: number;
1854
+ openingKind: "door" | "opening";
1855
+ openingShape: "rectangle" | "rounded" | "arch";
1856
+ openingRadiusMode: "all" | "individual";
1857
+ openingTopRadii: [number, number];
1858
+ cornerRadius: number;
1859
+ archHeight: number;
1860
+ openingRevealRadius: number;
1861
+ frameThickness: number;
1862
+ frameDepth: number;
1863
+ threshold: boolean;
1864
+ thresholdHeight: number;
1865
+ hingesSide: "right" | "left";
1866
+ swingDirection: "inward" | "outward";
1867
+ swingAngle: number;
1868
+ segments: {
1869
+ type: "glass" | "panel" | "empty";
1870
+ heightRatio: number;
1871
+ columnRatios: number[];
1872
+ dividerThickness: number;
1873
+ panelDepth: number;
1874
+ panelInset: number;
1875
+ }[];
1876
+ handle: boolean;
1877
+ handleHeight: number;
1878
+ handleSide: "right" | "left";
1879
+ contentPadding: [number, number];
1880
+ doorCloser: boolean;
1881
+ panicBar: boolean;
1882
+ panicBarHeight: number;
1883
+ type: "door";
1884
+ name?: string | undefined;
1885
+ camera?: {
1886
+ position: [number, number, number];
1887
+ target: [number, number, number];
1888
+ mode: "perspective" | "orthographic";
1889
+ fov?: number | undefined;
1890
+ zoom?: number | undefined;
1891
+ } | undefined;
1892
+ side?: "front" | "back" | undefined;
1893
+ wallId?: string | undefined;
1894
+ roofSegmentId?: string | undefined;
1895
+ roofFace?: "front" | "back" | "right" | "left" | undefined;
1896
+ slots?: Record<string, string> | undefined;
1897
+ material?: {
1898
+ id?: string | undefined;
1899
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1900
+ properties?: {
1901
+ color: string;
1902
+ roughness: number;
1903
+ metalness: number;
1904
+ opacity: number;
1905
+ transparent: boolean;
1906
+ side: "front" | "back" | "double";
1907
+ } | undefined;
1908
+ texture?: {
1909
+ url: string;
1910
+ repeat?: [number, number] | undefined;
1911
+ scale?: number | undefined;
1912
+ } | undefined;
1913
+ } | undefined;
1914
+ mark?: string | undefined;
1915
+ roughOpeningWidth?: number | undefined;
1916
+ roughOpeningHeight?: number | undefined;
1917
+ masonryOpeningWidth?: number | undefined;
1918
+ masonryOpeningHeight?: number | undefined;
1919
+ finishOpeningWidth?: number | undefined;
1920
+ finishOpeningHeight?: number | undefined;
1921
+ } | {
1922
+ object: "node";
1923
+ position: [number, number, number];
1924
+ id: `bvent_${string}`;
1925
+ parentId: string | null;
1926
+ visible: boolean;
1927
+ metadata: Record<string, unknown>;
1928
+ rotation: number;
1929
+ height: number;
1930
+ materialPreset: string;
1931
+ width: number;
1932
+ depth: number;
1933
+ hoodOverhang: number;
1934
+ topTaper: number;
1935
+ capHeight: number;
1936
+ capGap: number;
1937
+ domeCurvature: number;
1938
+ baseInset: number;
1939
+ baseHeight: number;
1940
+ cornerBevel: number;
1941
+ style: "box" | "cap" | "dome";
1942
+ type: "box-vent";
1943
+ name?: string | undefined;
1944
+ camera?: {
1945
+ position: [number, number, number];
1946
+ target: [number, number, number];
1947
+ mode: "perspective" | "orthographic";
1948
+ fov?: number | undefined;
1949
+ zoom?: number | undefined;
1950
+ } | undefined;
1951
+ roofSegmentId?: string | undefined;
1952
+ slots?: Record<string, string> | undefined;
1953
+ material?: {
1954
+ id?: string | undefined;
1955
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1956
+ properties?: {
1957
+ color: string;
1958
+ roughness: number;
1959
+ metalness: number;
1960
+ opacity: number;
1961
+ transparent: boolean;
1962
+ side: "front" | "back" | "double";
1963
+ } | undefined;
1964
+ texture?: {
1965
+ url: string;
1966
+ repeat?: [number, number] | undefined;
1967
+ scale?: number | undefined;
1968
+ } | undefined;
1969
+ } | undefined;
1970
+ } | {
1971
+ object: "node";
1972
+ length: number;
1973
+ position: [number, number, number];
1974
+ id: `rvent_${string}`;
1975
+ parentId: string | null;
1976
+ visible: boolean;
1977
+ metadata: Record<string, unknown>;
1978
+ rotation: number;
1979
+ height: number;
1980
+ width: number;
1981
+ style: "metal" | "standard" | "shingled";
1982
+ endCaps: boolean;
1983
+ type: "ridge-vent";
1984
+ name?: string | undefined;
1985
+ camera?: {
1986
+ position: [number, number, number];
1987
+ target: [number, number, number];
1988
+ mode: "perspective" | "orthographic";
1989
+ fov?: number | undefined;
1990
+ zoom?: number | undefined;
1991
+ } | undefined;
1992
+ roofSegmentId?: string | undefined;
1993
+ material?: {
1994
+ id?: string | undefined;
1995
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
1996
+ properties?: {
1997
+ color: string;
1998
+ roughness: number;
1999
+ metalness: number;
2000
+ opacity: number;
2001
+ transparent: boolean;
2002
+ side: "front" | "back" | "double";
2003
+ } | undefined;
2004
+ texture?: {
2005
+ url: string;
2006
+ repeat?: [number, number] | undefined;
2007
+ scale?: number | undefined;
2008
+ } | undefined;
2009
+ } | undefined;
2010
+ materialPreset?: string | undefined;
2011
+ } | {
2012
+ object: "node";
2013
+ position: [number, number, number];
2014
+ id: `tvent_${string}`;
2015
+ parentId: string | null;
2016
+ visible: boolean;
2017
+ metadata: Record<string, unknown>;
2018
+ rotation: number;
2019
+ height: number;
2020
+ materialPreset: string;
2021
+ style: "globe" | "cylinder";
2022
+ diameter: number;
2023
+ neckHeight: number;
2024
+ baseOverhang: number;
2025
+ vaneCount: number;
2026
+ spinSpeed: number;
2027
+ type: "turbine-vent";
2028
+ name?: string | undefined;
2029
+ camera?: {
2030
+ position: [number, number, number];
2031
+ target: [number, number, number];
2032
+ mode: "perspective" | "orthographic";
2033
+ fov?: number | undefined;
2034
+ zoom?: number | undefined;
2035
+ } | undefined;
2036
+ roofSegmentId?: string | undefined;
2037
+ slots?: Record<string, string> | undefined;
2038
+ material?: {
2039
+ id?: string | undefined;
2040
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2041
+ properties?: {
2042
+ color: string;
2043
+ roughness: number;
2044
+ metalness: number;
2045
+ opacity: number;
2046
+ transparent: boolean;
2047
+ side: "front" | "back" | "double";
2048
+ } | undefined;
2049
+ texture?: {
2050
+ url: string;
2051
+ repeat?: [number, number] | undefined;
2052
+ scale?: number | undefined;
2053
+ } | undefined;
2054
+ } | undefined;
2055
+ } | {
2056
+ object: "node";
2057
+ position: [number, number, number];
2058
+ id: `cupola_${string}`;
2059
+ parentId: string | null;
2060
+ visible: boolean;
2061
+ metadata: Record<string, unknown>;
2062
+ rotation: number;
2063
+ height: number;
2064
+ materialPreset: string;
2065
+ width: number;
2066
+ depth: number;
2067
+ roofStyle: "dome" | "pyramid";
2068
+ finial: boolean;
2069
+ type: "cupola";
2070
+ name?: string | undefined;
2071
+ camera?: {
2072
+ position: [number, number, number];
2073
+ target: [number, number, number];
2074
+ mode: "perspective" | "orthographic";
2075
+ fov?: number | undefined;
2076
+ zoom?: number | undefined;
2077
+ } | undefined;
2078
+ roofSegmentId?: string | undefined;
2079
+ slots?: Record<string, string> | undefined;
2080
+ material?: {
2081
+ id?: string | undefined;
2082
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2083
+ properties?: {
2084
+ color: string;
2085
+ roughness: number;
2086
+ metalness: number;
2087
+ opacity: number;
2088
+ transparent: boolean;
2089
+ side: "front" | "back" | "double";
2090
+ } | undefined;
2091
+ texture?: {
2092
+ url: string;
2093
+ repeat?: [number, number] | undefined;
2094
+ scale?: number | undefined;
2095
+ } | undefined;
2096
+ } | undefined;
2097
+ } | {
2098
+ object: "node";
2099
+ position: [number, number, number];
2100
+ id: `eyebrow-vent_${string}`;
2101
+ parentId: string | null;
2102
+ visible: boolean;
2103
+ metadata: Record<string, unknown>;
2104
+ rotation: number;
2105
+ height: number;
2106
+ materialPreset: string;
2107
+ width: number;
2108
+ depth: number;
2109
+ style: "half-round" | "scoop" | "slant-box";
2110
+ louverCount: number;
2111
+ backRatio: number;
2112
+ type: "eyebrow-vent";
2113
+ name?: string | undefined;
2114
+ camera?: {
2115
+ position: [number, number, number];
2116
+ target: [number, number, number];
2117
+ mode: "perspective" | "orthographic";
2118
+ fov?: number | undefined;
2119
+ zoom?: number | undefined;
2120
+ } | undefined;
2121
+ roofSegmentId?: string | undefined;
2122
+ slots?: Record<string, string> | undefined;
2123
+ material?: {
2124
+ id?: string | undefined;
2125
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2126
+ properties?: {
2127
+ color: string;
2128
+ roughness: number;
2129
+ metalness: number;
2130
+ opacity: number;
2131
+ transparent: boolean;
2132
+ side: "front" | "back" | "double";
2133
+ } | undefined;
2134
+ texture?: {
2135
+ url: string;
2136
+ repeat?: [number, number] | undefined;
2137
+ scale?: number | undefined;
2138
+ } | undefined;
2139
+ } | undefined;
2140
+ } | {
2141
+ object: "node";
2142
+ length: number;
2143
+ position: [number, number, number];
2144
+ id: `gutter_${string}`;
2145
+ parentId: string | null;
2146
+ visible: boolean;
2147
+ metadata: Record<string, unknown>;
2148
+ rotation: number;
2149
+ materialPreset: string;
2150
+ thickness: number;
2151
+ profile: "box" | "k-style" | "half-round";
2152
+ hangerStyle: "none" | "strap";
2153
+ hangerSpacing: number;
2154
+ size: number;
2155
+ endCapLeft: boolean;
2156
+ endCapRight: boolean;
2157
+ outlets: {
2158
+ id: string;
2159
+ offset: number;
2160
+ diameter: number;
2161
+ generatedBy?: "default-downspout" | undefined;
2162
+ }[];
2163
+ type: "gutter";
2164
+ name?: string | undefined;
2165
+ camera?: {
2166
+ position: [number, number, number];
2167
+ target: [number, number, number];
2168
+ mode: "perspective" | "orthographic";
2169
+ fov?: number | undefined;
2170
+ zoom?: number | undefined;
2171
+ } | undefined;
2172
+ roofSegmentId?: string | undefined;
2173
+ slots?: Record<string, string> | undefined;
2174
+ material?: {
2175
+ id?: string | undefined;
2176
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2177
+ properties?: {
2178
+ color: string;
2179
+ roughness: number;
2180
+ metalness: number;
2181
+ opacity: number;
2182
+ transparent: boolean;
2183
+ side: "front" | "back" | "double";
2184
+ } | undefined;
2185
+ texture?: {
2186
+ url: string;
2187
+ repeat?: [number, number] | undefined;
2188
+ scale?: number | undefined;
2189
+ } | undefined;
2190
+ } | undefined;
2191
+ arc?: {
2192
+ centerX: number;
2193
+ centerZ: number;
2194
+ radius: number;
2195
+ } | undefined;
2196
+ } | {
2197
+ object: "node";
2198
+ position: [number, number, number];
2199
+ id: `chimney_${string}`;
2200
+ parentId: string | null;
2201
+ visible: boolean;
2202
+ metadata: Record<string, unknown>;
2203
+ rotation: number;
2204
+ width: number;
2205
+ depth: number;
2206
+ cornerBevel: number;
2207
+ cap: boolean;
2208
+ panelDepth: number;
2209
+ panelHeight: number;
2210
+ bodyShape: "round" | "square";
2211
+ bodyHollowDepth: number;
2212
+ bodyHollowMargin: number;
2213
+ heightAboveRidge: number;
2214
+ cutoutOffset: number;
2215
+ capShape: "flat" | "none" | "stepped" | "sloped";
2216
+ capOverhang: number;
2217
+ capThickness: number;
2218
+ flueCount: number;
2219
+ flueShape: "round" | "square";
2220
+ flueHeight: number;
2221
+ flueDiameter: number;
2222
+ flueSpacing: number;
2223
+ flueWallThickness: number;
2224
+ shoulderStyle: "tapered" | "none" | "corbeled";
2225
+ shoulderHeight: number;
2226
+ shoulderExtent: number;
2227
+ bandStyle: "double" | "none" | "single";
2228
+ bandHeight: number;
2229
+ bandExtent: number;
2230
+ bandOffset: number;
2231
+ cricketStyle: "none" | "simple";
2232
+ cricketLength: number;
2233
+ cricketHeight: number;
2234
+ cricketSide: "front" | "back";
2235
+ panelStyle: "rectangular" | "none";
2236
+ panelOffsetTop: number;
2237
+ panelMargin: number;
2238
+ type: "chimney";
2239
+ name?: string | undefined;
2240
+ camera?: {
2241
+ position: [number, number, number];
2242
+ target: [number, number, number];
2243
+ mode: "perspective" | "orthographic";
2244
+ fov?: number | undefined;
2245
+ zoom?: number | undefined;
2246
+ } | undefined;
2247
+ roofSegmentId?: string | undefined;
2248
+ material?: {
2249
+ id?: string | undefined;
2250
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2251
+ properties?: {
2252
+ color: string;
2253
+ roughness: number;
2254
+ metalness: number;
2255
+ opacity: number;
2256
+ transparent: boolean;
2257
+ side: "front" | "back" | "double";
2258
+ } | undefined;
2259
+ texture?: {
2260
+ url: string;
2261
+ repeat?: [number, number] | undefined;
2262
+ scale?: number | undefined;
2263
+ } | undefined;
2264
+ } | undefined;
2265
+ materialPreset?: string | undefined;
2266
+ topMaterial?: {
2267
+ id?: string | undefined;
2268
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2269
+ properties?: {
2270
+ color: string;
2271
+ roughness: number;
2272
+ metalness: number;
2273
+ opacity: number;
2274
+ transparent: boolean;
2275
+ side: "front" | "back" | "double";
2276
+ } | undefined;
2277
+ texture?: {
2278
+ url: string;
2279
+ repeat?: [number, number] | undefined;
2280
+ scale?: number | undefined;
2281
+ } | undefined;
2282
+ } | undefined;
2283
+ topMaterialPreset?: string | undefined;
2284
+ } | {
2285
+ object: "node";
2286
+ position: [number, number, number];
2287
+ id: `solarpanel_${string}`;
2288
+ parentId: string | null;
2289
+ visible: boolean;
2290
+ metadata: Record<string, unknown>;
2291
+ rotation: number;
2292
+ rows: number;
2293
+ frameThickness: number;
2294
+ frameDepth: number;
2295
+ columns: number;
2296
+ panelWidth: number;
2297
+ panelHeight: number;
2298
+ gapX: number;
2299
+ gapY: number;
2300
+ mountingType: "flush" | "tilted";
2301
+ tiltAngle: number;
2302
+ standoffHeight: number;
2303
+ type: "solar-panel";
2304
+ name?: string | undefined;
2305
+ camera?: {
2306
+ position: [number, number, number];
2307
+ target: [number, number, number];
2308
+ mode: "perspective" | "orthographic";
2309
+ fov?: number | undefined;
2310
+ zoom?: number | undefined;
2311
+ } | undefined;
2312
+ roofSegmentId?: string | undefined;
2313
+ material?: {
2314
+ id?: string | undefined;
2315
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2316
+ properties?: {
2317
+ color: string;
2318
+ roughness: number;
2319
+ metalness: number;
2320
+ opacity: number;
2321
+ transparent: boolean;
2322
+ side: "front" | "back" | "double";
2323
+ } | undefined;
2324
+ texture?: {
2325
+ url: string;
2326
+ repeat?: [number, number] | undefined;
2327
+ scale?: number | undefined;
2328
+ } | undefined;
2329
+ } | undefined;
2330
+ materialPreset?: string | undefined;
2331
+ panelMaterial?: {
2332
+ id?: string | undefined;
2333
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2334
+ properties?: {
2335
+ color: string;
2336
+ roughness: number;
2337
+ metalness: number;
2338
+ opacity: number;
2339
+ transparent: boolean;
2340
+ side: "front" | "back" | "double";
2341
+ } | undefined;
2342
+ texture?: {
2343
+ url: string;
2344
+ repeat?: [number, number] | undefined;
2345
+ scale?: number | undefined;
2346
+ } | undefined;
2347
+ } | undefined;
2348
+ panelMaterialPreset?: string | undefined;
2349
+ panelTypePreset?: "residential" | "residential-large" | "compact" | "frameless" | undefined;
2350
+ surfaceNormal?: [number, number, number] | undefined;
2351
+ } | {
2352
+ object: "node";
2353
+ position: [number, number, number];
2354
+ id: `skylight_${string}`;
2355
+ parentId: string | null;
2356
+ visible: boolean;
2357
+ metadata: Record<string, unknown>;
2358
+ rotation: number;
2359
+ height: number;
2360
+ width: number;
2361
+ operationState: number;
2362
+ slideDirection: "z" | "x";
2363
+ frameThickness: number;
2364
+ frameDepth: number;
2365
+ curbHeight: number;
2366
+ cutoutOffset: number;
2367
+ skylightType: "flat" | "sliding" | "opening" | "walk-on" | "lantern";
2368
+ glassThickness: number;
2369
+ lanternHeight: number;
2370
+ lanternTopScale: number;
2371
+ openingAngle: number;
2372
+ openingSide: "right" | "left" | "top" | "bottom";
2373
+ motorHousing: boolean;
2374
+ slideFraction: number;
2375
+ trackWidth: number;
2376
+ motorHousingSize: number;
2377
+ curb: boolean;
2378
+ type: "skylight";
2379
+ name?: string | undefined;
2380
+ camera?: {
2381
+ position: [number, number, number];
2382
+ target: [number, number, number];
2383
+ mode: "perspective" | "orthographic";
2384
+ fov?: number | undefined;
2385
+ zoom?: number | undefined;
2386
+ } | undefined;
2387
+ roofSegmentId?: string | undefined;
2388
+ material?: {
2389
+ id?: string | undefined;
2390
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2391
+ properties?: {
2392
+ color: string;
2393
+ roughness: number;
2394
+ metalness: number;
2395
+ opacity: number;
2396
+ transparent: boolean;
2397
+ side: "front" | "back" | "double";
2398
+ } | undefined;
2399
+ texture?: {
2400
+ url: string;
2401
+ repeat?: [number, number] | undefined;
2402
+ scale?: number | undefined;
2403
+ } | undefined;
2404
+ } | undefined;
2405
+ materialPreset?: string | undefined;
2406
+ surfaceNormal?: [number, number, number] | undefined;
2407
+ glassMaterial?: {
2408
+ id?: string | undefined;
2409
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2410
+ properties?: {
2411
+ color: string;
2412
+ roughness: number;
2413
+ metalness: number;
2414
+ opacity: number;
2415
+ transparent: boolean;
2416
+ side: "front" | "back" | "double";
2417
+ } | undefined;
2418
+ texture?: {
2419
+ url: string;
2420
+ repeat?: [number, number] | undefined;
2421
+ scale?: number | undefined;
2422
+ } | undefined;
2423
+ } | undefined;
2424
+ glassMaterialPreset?: string | undefined;
2425
+ } | {
2426
+ object: "node";
2427
+ position: [number, number, number];
2428
+ id: `dormer_${string}`;
2429
+ parentId: string | null;
2430
+ visible: boolean;
2431
+ metadata: Record<string, unknown>;
2432
+ rotation: number;
2433
+ height: number;
2434
+ children: `window_${string}`[];
2435
+ width: number;
2436
+ depth: number;
2437
+ roofType: "flat" | "hip" | "gable" | "shed" | "gambrel" | "dutch" | "mansard" | "conical";
2438
+ roofHeight: number;
2439
+ shedHighSide: "front" | "back";
2440
+ wallSkirtHeight: number;
2441
+ windowWidth: number;
2442
+ windowHeight: number;
2443
+ windowOffsetX: number;
2444
+ windowOffsetY: number;
2445
+ windowFrameThickness: number;
2446
+ windowFrameDepth: number;
2447
+ windowColumns: number;
2448
+ windowRows: number;
2449
+ windowDividerThickness: number;
2450
+ windowShape: "rectangle" | "rounded" | "arch";
2451
+ windowArchHeight: number;
2452
+ windowCornerRadii: [number, number, number, number];
2453
+ windowSill: boolean;
2454
+ windowSillDepth: number;
2455
+ windowSillThickness: number;
2456
+ type: "dormer";
2457
+ name?: string | undefined;
2458
+ camera?: {
2459
+ position: [number, number, number];
2460
+ target: [number, number, number];
2461
+ mode: "perspective" | "orthographic";
2462
+ fov?: number | undefined;
2463
+ zoom?: number | undefined;
2464
+ } | undefined;
2465
+ roofSegmentId?: string | undefined;
2466
+ material?: {
2467
+ id?: string | undefined;
2468
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2469
+ properties?: {
2470
+ color: string;
2471
+ roughness: number;
2472
+ metalness: number;
2473
+ opacity: number;
2474
+ transparent: boolean;
2475
+ side: "front" | "back" | "double";
2476
+ } | undefined;
2477
+ texture?: {
2478
+ url: string;
2479
+ repeat?: [number, number] | undefined;
2480
+ scale?: number | undefined;
2481
+ } | undefined;
2482
+ } | undefined;
2483
+ materialPreset?: string | undefined;
2484
+ topMaterial?: {
2485
+ id?: string | undefined;
2486
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2487
+ properties?: {
2488
+ color: string;
2489
+ roughness: number;
2490
+ metalness: number;
2491
+ opacity: number;
2492
+ transparent: boolean;
2493
+ side: "front" | "back" | "double";
2494
+ } | undefined;
2495
+ texture?: {
2496
+ url: string;
2497
+ repeat?: [number, number] | undefined;
2498
+ scale?: number | undefined;
2499
+ } | undefined;
2500
+ } | undefined;
2501
+ topMaterialPreset?: string | undefined;
2502
+ wallMaterial?: {
2503
+ id?: string | undefined;
2504
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2505
+ properties?: {
2506
+ color: string;
2507
+ roughness: number;
2508
+ metalness: number;
2509
+ opacity: number;
2510
+ transparent: boolean;
2511
+ side: "front" | "back" | "double";
2512
+ } | undefined;
2513
+ texture?: {
2514
+ url: string;
2515
+ repeat?: [number, number] | undefined;
2516
+ scale?: number | undefined;
2517
+ } | undefined;
2518
+ } | undefined;
2519
+ wallMaterialPreset?: string | undefined;
2520
+ sideMaterial?: {
2521
+ id?: string | undefined;
2522
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2523
+ properties?: {
2524
+ color: string;
2525
+ roughness: number;
2526
+ metalness: number;
2527
+ opacity: number;
2528
+ transparent: boolean;
2529
+ side: "front" | "back" | "double";
2530
+ } | undefined;
2531
+ texture?: {
2532
+ url: string;
2533
+ repeat?: [number, number] | undefined;
2534
+ scale?: number | undefined;
2535
+ } | undefined;
2536
+ } | undefined;
2537
+ sideMaterialPreset?: string | undefined;
2538
+ } | {
2539
+ object: "node";
2540
+ length: number;
2541
+ id: `downspout_${string}`;
2542
+ parentId: string | null;
2543
+ visible: boolean;
2544
+ metadata: Record<string, unknown>;
2545
+ materialPreset: string;
2546
+ diameter: number;
2547
+ shape: "round" | "auto" | "rect";
2548
+ standoff: number;
2549
+ strapStyle: "none" | "band";
2550
+ strapSpacing: number;
2551
+ terminal: "straight" | "splash" | "kickout";
2552
+ type: "downspout";
2553
+ name?: string | undefined;
2554
+ camera?: {
2555
+ position: [number, number, number];
2556
+ target: [number, number, number];
2557
+ mode: "perspective" | "orthographic";
2558
+ fov?: number | undefined;
2559
+ zoom?: number | undefined;
2560
+ } | undefined;
2561
+ slots?: Record<string, string> | undefined;
2562
+ material?: {
2563
+ id?: string | undefined;
2564
+ preset?: "custom" | "white" | "brick" | "concrete" | "wood" | "glass" | "metal" | "plaster" | "tile" | "marble" | undefined;
2565
+ properties?: {
2566
+ color: string;
2567
+ roughness: number;
2568
+ metalness: number;
2569
+ opacity: number;
2570
+ transparent: boolean;
2571
+ side: "front" | "back" | "double";
2572
+ } | undefined;
2573
+ texture?: {
2574
+ url: string;
2575
+ repeat?: [number, number] | undefined;
2576
+ scale?: number | undefined;
2577
+ } | undefined;
2578
+ } | undefined;
2579
+ gutterId?: string | undefined;
2580
+ outletId?: string | undefined;
2581
+ lengthMode?: "manual" | "to-ground" | undefined;
2582
+ } | {
2583
+ object: "node";
2584
+ path: [number, number, number][];
2585
+ id: `duct-segment_${string}`;
2586
+ parentId: string | null;
2587
+ visible: boolean;
2588
+ metadata: Record<string, unknown>;
2589
+ height: number;
2590
+ width: number;
2591
+ diameter: number;
2592
+ shape: "round" | "rect" | "oval";
2593
+ roll: number;
2594
+ ductMaterial: "spiral" | "sheet-metal" | "flex" | "duct-board";
2595
+ seamDetail: boolean;
2596
+ insulated: boolean;
2597
+ insulationR: number;
2598
+ system: "supply" | "return";
2599
+ type: "duct-segment";
2600
+ name?: string | undefined;
2601
+ camera?: {
2602
+ position: [number, number, number];
2603
+ target: [number, number, number];
2604
+ mode: "perspective" | "orthographic";
2605
+ fov?: number | undefined;
2606
+ zoom?: number | undefined;
2607
+ } | undefined;
2608
+ slots?: Record<string, string> | undefined;
2609
+ autoHangers?: boolean | undefined;
2610
+ hangerOverrides?: Record<string, {
2611
+ fraction?: number | undefined;
2612
+ skipped?: boolean | undefined;
2613
+ hostId?: string | undefined;
2614
+ }> | undefined;
2615
+ hangerStyle?: "double" | "single" | undefined;
2616
+ hangerSpacing?: number | undefined;
2617
+ hangerMaxReach?: number | undefined;
2618
+ wallAttachment?: {
2619
+ wallId: `wall_${string}`;
2620
+ side: "front" | "back";
2621
+ startUV: [number, number];
2622
+ endUV: [number, number];
2623
+ offset: number;
2624
+ } | undefined;
2625
+ } | {
2626
+ object: "node";
2627
+ position: [number, number, number];
2628
+ id: `duct-fitting_${string}`;
2629
+ parentId: string | null;
2630
+ visible: boolean;
2631
+ metadata: Record<string, unknown>;
2632
+ rotation: [number, number, number];
2633
+ height: number;
2634
+ width: number;
2635
+ diameter: number;
2636
+ angle: number;
2637
+ shape: "round" | "rect" | "oval";
2638
+ ductMaterial: "sheet-metal" | "flex" | "duct-board";
2639
+ system: "supply" | "return";
2640
+ fittingType: "elbow" | "tee" | "cross" | "reducer" | "transition" | "end-cap" | "damper" | "access-panel" | "coupling";
2641
+ shape2: "round" | "rect" | "oval";
2642
+ width2: number;
2643
+ height2: number;
2644
+ branchAngle: number;
2645
+ diameter2: number;
2646
+ damperAngle: number;
2647
+ panelWidth: number;
2648
+ panelHeight: number;
2649
+ type: "duct-fitting";
2650
+ name?: string | undefined;
2651
+ camera?: {
2652
+ position: [number, number, number];
2653
+ target: [number, number, number];
2654
+ mode: "perspective" | "orthographic";
2655
+ fov?: number | undefined;
2656
+ zoom?: number | undefined;
2657
+ } | undefined;
2658
+ slots?: Record<string, string> | undefined;
2659
+ inletShape?: "round" | "rect" | "oval" | undefined;
2660
+ outletShape?: "round" | "rect" | "oval" | undefined;
2661
+ } | {
2662
+ object: "node";
2663
+ position: [number, number, number];
2664
+ id: `duct-terminal_${string}`;
2665
+ parentId: string | null;
2666
+ visible: boolean;
2667
+ metadata: Record<string, unknown>;
2668
+ rotation: number;
2669
+ width: number;
2670
+ depth: number;
2671
+ terminalType: "supply-register" | "diffuser" | "return-grille";
2672
+ mount: "wall" | "ceiling" | "floor";
2673
+ collarShape: "round" | "rect" | "oval";
2674
+ collarDiameter: number;
2675
+ collarWidth: number;
2676
+ collarHeight: number;
2677
+ type: "duct-terminal";
2678
+ name?: string | undefined;
2679
+ camera?: {
2680
+ position: [number, number, number];
2681
+ target: [number, number, number];
2682
+ mode: "perspective" | "orthographic";
2683
+ fov?: number | undefined;
2684
+ zoom?: number | undefined;
2685
+ } | undefined;
2686
+ supportSlabId?: string | undefined;
2687
+ } | {
2688
+ object: "node";
2689
+ position: [number, number, number];
2690
+ id: `hvac-equipment_${string}`;
2691
+ parentId: string | null;
2692
+ visible: boolean;
2693
+ metadata: Record<string, unknown>;
2694
+ rotation: number;
2695
+ height: number;
2696
+ width: number;
2697
+ depth: number;
2698
+ equipmentType: "furnace" | "air-handler" | "condenser";
2699
+ supplyShape: "round" | "rect" | "oval";
2700
+ returnShape: "round" | "rect" | "oval";
2701
+ supplyDiameter: number;
2702
+ returnDiameter: number;
2703
+ supplyWidth: number;
2704
+ supplyHeight: number;
2705
+ returnWidth: number;
2706
+ returnHeight: number;
2707
+ type: "hvac-equipment";
2708
+ name?: string | undefined;
2709
+ camera?: {
2710
+ position: [number, number, number];
2711
+ target: [number, number, number];
2712
+ mode: "perspective" | "orthographic";
2713
+ fov?: number | undefined;
2714
+ zoom?: number | undefined;
2715
+ } | undefined;
2716
+ supportSlabId?: string | undefined;
2717
+ } | {
2718
+ object: "node";
2719
+ path: [number, number, number][];
2720
+ id: `lineset_${string}`;
2721
+ parentId: string | null;
2722
+ visible: boolean;
2723
+ metadata: Record<string, unknown>;
2724
+ insulated: boolean;
2725
+ suctionDiameter: number;
2726
+ liquidDiameter: number;
2727
+ type: "lineset";
2728
+ name?: string | undefined;
2729
+ camera?: {
2730
+ position: [number, number, number];
2731
+ target: [number, number, number];
2732
+ mode: "perspective" | "orthographic";
2733
+ fov?: number | undefined;
2734
+ zoom?: number | undefined;
2735
+ } | undefined;
2736
+ } | {
2737
+ object: "node";
2738
+ path: [number, number, number][];
2739
+ id: `liquid-line_${string}`;
2740
+ parentId: string | null;
2741
+ visible: boolean;
2742
+ metadata: Record<string, unknown>;
2743
+ diameter: number;
2744
+ type: "liquid-line";
2745
+ name?: string | undefined;
2746
+ camera?: {
2747
+ position: [number, number, number];
2748
+ target: [number, number, number];
2749
+ mode: "perspective" | "orthographic";
2750
+ fov?: number | undefined;
2751
+ zoom?: number | undefined;
2752
+ } | undefined;
2753
+ } | {
2754
+ object: "node";
2755
+ path: [number, number, number][];
2756
+ id: `pipe-segment_${string}`;
2757
+ parentId: string | null;
2758
+ visible: boolean;
2759
+ metadata: Record<string, unknown>;
2760
+ diameter: number;
2761
+ system: "waste" | "vent";
2762
+ pipeMaterial: "pvc" | "abs" | "cast-iron";
2763
+ type: "pipe-segment";
2764
+ name?: string | undefined;
2765
+ camera?: {
2766
+ position: [number, number, number];
2767
+ target: [number, number, number];
2768
+ mode: "perspective" | "orthographic";
2769
+ fov?: number | undefined;
2770
+ zoom?: number | undefined;
2771
+ } | undefined;
2772
+ autoHangers?: boolean | undefined;
2773
+ hangerOverrides?: Record<string, {
2774
+ fraction?: number | undefined;
2775
+ skipped?: boolean | undefined;
2776
+ hostId?: string | undefined;
2777
+ }> | undefined;
2778
+ hangerStyle?: "double" | "single" | undefined;
2779
+ hangerSpacing?: number | undefined;
2780
+ hangerMaxReach?: number | undefined;
2781
+ wallAttachment?: {
2782
+ wallId: `wall_${string}`;
2783
+ side: "front" | "back";
2784
+ startUV: [number, number];
2785
+ endUV: [number, number];
2786
+ offset: number;
2787
+ } | undefined;
2788
+ } | {
2789
+ object: "node";
2790
+ position: [number, number, number];
2791
+ id: `pipe-fitting_${string}`;
2792
+ parentId: string | null;
2793
+ visible: boolean;
2794
+ metadata: Record<string, unknown>;
2795
+ rotation: [number, number, number];
2796
+ diameter: number;
2797
+ angle: number;
2798
+ system: "waste" | "vent";
2799
+ fittingType: "elbow" | "cross" | "reducer" | "end-cap" | "coupling" | "wye" | "sanitary-tee" | "cleanout";
2800
+ diameter2: number;
2801
+ pipeMaterial: "pvc" | "abs" | "cast-iron";
2802
+ cleanoutStyle: "end" | "inline";
2803
+ type: "pipe-fitting";
2804
+ name?: string | undefined;
2805
+ camera?: {
2806
+ position: [number, number, number];
2807
+ target: [number, number, number];
2808
+ mode: "perspective" | "orthographic";
2809
+ fov?: number | undefined;
2810
+ zoom?: number | undefined;
2811
+ } | undefined;
2812
+ } | {
2813
+ object: "node";
2814
+ position: [number, number, number];
2815
+ id: `pipe-trap_${string}`;
2816
+ parentId: string | null;
2817
+ visible: boolean;
2818
+ metadata: Record<string, unknown>;
2819
+ rotation: number;
2820
+ diameter: number;
2821
+ pipeMaterial: "pvc" | "abs" | "cast-iron";
2822
+ armLengthM: number;
2823
+ type: "pipe-trap";
2824
+ name?: string | undefined;
2825
+ camera?: {
2826
+ position: [number, number, number];
2827
+ target: [number, number, number];
2828
+ mode: "perspective" | "orthographic";
2829
+ fov?: number | undefined;
2830
+ zoom?: number | undefined;
2831
+ } | undefined;
2832
+ }>): void;
49
2833
  /**
50
2834
  * The sculpted ground moved: every node the terrain *supports* must re-elevate.
51
2835
  *