@snaptrude/plugin-core 0.11.0-rc.1 → 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 (226) hide show
  1. package/AGENTS.md +4 -0
  2. package/CHANGELOG.md +176 -14
  3. package/api-manifest.json +872 -49
  4. package/dist/api/analysis/daylight.d.ts +5 -5
  5. package/dist/api/analysis/solar.d.ts +2 -2
  6. package/dist/api/core/camera/index.d.ts +447 -0
  7. package/dist/api/core/camera/index.d.ts.map +1 -1
  8. package/dist/api/core/geom/create/index.d.ts +942 -101
  9. package/dist/api/core/geom/create/index.d.ts.map +1 -1
  10. package/dist/api/core/geom/query/brep.d.ts +59 -2
  11. package/dist/api/core/geom/query/brep.d.ts.map +1 -1
  12. package/dist/api/core/geom/query/curve.d.ts +59 -35
  13. package/dist/api/core/geom/query/curve.d.ts.map +1 -1
  14. package/dist/api/core/geom/query/edge.d.ts +2 -2
  15. package/dist/api/core/geom/query/face.d.ts +105 -0
  16. package/dist/api/core/geom/query/face.d.ts.map +1 -1
  17. package/dist/api/core/geom/update/contour.d.ts +10 -2
  18. package/dist/api/core/geom/update/contour.d.ts.map +1 -1
  19. package/dist/api/core/geom/update/curve.d.ts +5 -5
  20. package/dist/api/core/geom/update/profile.d.ts +3 -1
  21. package/dist/api/core/geom/update/profile.d.ts.map +1 -1
  22. package/dist/api/core/handles/index.d.ts +4 -2
  23. package/dist/api/core/handles/index.d.ts.map +1 -1
  24. package/dist/api/core/index.d.ts +4 -4
  25. package/dist/api/core/index.d.ts.map +1 -1
  26. package/dist/api/core/io/import/index.d.ts +3 -1
  27. package/dist/api/core/io/import/index.d.ts.map +1 -1
  28. package/dist/api/core/layers.d.ts +377 -255
  29. package/dist/api/core/layers.d.ts.map +1 -1
  30. package/dist/api/core/mode/index.d.ts +19 -7
  31. package/dist/api/core/mode/index.d.ts.map +1 -1
  32. package/dist/api/core/proposals/index.d.ts +4 -3
  33. package/dist/api/core/proposals/index.d.ts.map +1 -1
  34. package/dist/api/core/storeys/index.d.ts +17 -2
  35. package/dist/api/core/storeys/index.d.ts.map +1 -1
  36. package/dist/api/core/storeys/layers.d.ts +408 -0
  37. package/dist/api/core/storeys/layers.d.ts.map +1 -0
  38. package/dist/api/core/tags.d.ts +84 -3
  39. package/dist/api/core/tags.d.ts.map +1 -1
  40. package/dist/api/core/zoom/index.d.ts +13 -0
  41. package/dist/api/core/zoom/index.d.ts.map +1 -1
  42. package/dist/api/design/bim.d.ts +299 -0
  43. package/dist/api/design/bim.d.ts.map +1 -0
  44. package/dist/api/design/boolean/index.d.ts +2 -0
  45. package/dist/api/design/boolean/index.d.ts.map +1 -1
  46. package/dist/api/design/catalog.d.ts +320 -0
  47. package/dist/api/design/catalog.d.ts.map +1 -0
  48. package/dist/api/design/create/bulk-items.d.ts +269 -0
  49. package/dist/api/design/create/bulk-items.d.ts.map +1 -0
  50. package/dist/api/design/create/grids.d.ts +132 -0
  51. package/dist/api/design/create/grids.d.ts.map +1 -0
  52. package/dist/api/design/create/index.d.ts +753 -102
  53. package/dist/api/design/create/index.d.ts.map +1 -1
  54. package/dist/api/design/create/opening-fields.d.ts +38 -0
  55. package/dist/api/design/create/opening-fields.d.ts.map +1 -0
  56. package/dist/api/design/delete/index.d.ts +7 -20
  57. package/dist/api/design/delete/index.d.ts.map +1 -1
  58. package/dist/api/design/dimensions.d.ts +427 -0
  59. package/dist/api/design/dimensions.d.ts.map +1 -0
  60. package/dist/api/design/doors/index.d.ts +24 -23
  61. package/dist/api/design/doors/index.d.ts.map +1 -1
  62. package/dist/api/design/family.d.ts +1446 -0
  63. package/dist/api/design/family.d.ts.map +1 -0
  64. package/dist/api/design/grids.d.ts +237 -0
  65. package/dist/api/design/grids.d.ts.map +1 -0
  66. package/dist/api/design/index.d.ts +30 -0
  67. package/dist/api/design/index.d.ts.map +1 -1
  68. package/dist/api/design/networks.d.ts +1703 -0
  69. package/dist/api/design/networks.d.ts.map +1 -0
  70. package/dist/api/design/query/geometry/index.d.ts +33 -5
  71. package/dist/api/design/query/geometry/index.d.ts.map +1 -1
  72. package/dist/api/design/query/grids.d.ts +287 -0
  73. package/dist/api/design/query/grids.d.ts.map +1 -0
  74. package/dist/api/design/query/index.d.ts +143 -36
  75. package/dist/api/design/query/index.d.ts.map +1 -1
  76. package/dist/api/design/query/spaces.d.ts +5 -66
  77. package/dist/api/design/query/spaces.d.ts.map +1 -1
  78. package/dist/api/design/selection/index.d.ts +12 -12
  79. package/dist/api/design/types/index.d.ts +40 -24
  80. package/dist/api/design/types/index.d.ts.map +1 -1
  81. package/dist/api/design/update/index.d.ts +412 -8
  82. package/dist/api/design/update/index.d.ts.map +1 -1
  83. package/dist/api/design/windows/index.d.ts +8 -8
  84. package/dist/api/design/windows/index.d.ts.map +1 -1
  85. package/dist/api/entity/buildableEnvelope.d.ts +84 -2
  86. package/dist/api/entity/buildableEnvelope.d.ts.map +1 -1
  87. package/dist/api/entity/referenceLine.d.ts +13 -1
  88. package/dist/api/entity/referenceLine.d.ts.map +1 -1
  89. package/dist/api/entity/space.d.ts +12 -15
  90. package/dist/api/entity/space.d.ts.map +1 -1
  91. package/dist/api/entity/story.d.ts +4 -4
  92. package/dist/api/presentation/aiInspiration.d.ts +24 -24
  93. package/dist/api/presentation/annotate.d.ts +38 -22
  94. package/dist/api/presentation/annotate.d.ts.map +1 -1
  95. package/dist/api/presentation/camera.d.ts +265 -0
  96. package/dist/api/presentation/camera.d.ts.map +1 -0
  97. package/dist/api/presentation/drawingContract.d.ts +32 -0
  98. package/dist/api/presentation/drawingContract.d.ts.map +1 -0
  99. package/dist/api/presentation/drawings.d.ts +3523 -0
  100. package/dist/api/presentation/drawings.d.ts.map +1 -0
  101. package/dist/api/presentation/export.d.ts +23 -5
  102. package/dist/api/presentation/export.d.ts.map +1 -1
  103. package/dist/api/presentation/graphics.d.ts +419 -0
  104. package/dist/api/presentation/graphics.d.ts.map +1 -0
  105. package/dist/api/presentation/index.d.ts +66 -12
  106. package/dist/api/presentation/index.d.ts.map +1 -1
  107. package/dist/api/presentation/placedViews.d.ts +117 -51
  108. package/dist/api/presentation/placedViews.d.ts.map +1 -1
  109. package/dist/api/presentation/sections.d.ts +461 -0
  110. package/dist/api/presentation/sections.d.ts.map +1 -0
  111. package/dist/api/presentation/shapes.d.ts +2 -2
  112. package/dist/api/presentation/sheets.d.ts +175 -37
  113. package/dist/api/presentation/sheets.d.ts.map +1 -1
  114. package/dist/api/presentation/standards.d.ts +590 -0
  115. package/dist/api/presentation/standards.d.ts.map +1 -0
  116. package/dist/api/presentation/viewPresets.d.ts +222 -0
  117. package/dist/api/presentation/viewPresets.d.ts.map +1 -0
  118. package/dist/api/presentation/views.d.ts +144 -9
  119. package/dist/api/presentation/views.d.ts.map +1 -1
  120. package/dist/api/presentation/walkthroughs.d.ts +1350 -0
  121. package/dist/api/presentation/walkthroughs.d.ts.map +1 -0
  122. package/dist/api/program/departments.d.ts +58 -2
  123. package/dist/api/program/departments.d.ts.map +1 -1
  124. package/dist/api/program/index.d.ts +16 -6
  125. package/dist/api/program/index.d.ts.map +1 -1
  126. package/dist/api/program/labels.d.ts +355 -0
  127. package/dist/api/program/labels.d.ts.map +1 -0
  128. package/dist/api/program/metadata.d.ts +328 -0
  129. package/dist/api/program/metadata.d.ts.map +1 -0
  130. package/dist/api/program/site.d.ts +4 -4
  131. package/dist/api/program/spreadsheet.d.ts +267 -4
  132. package/dist/api/program/spreadsheet.d.ts.map +1 -1
  133. package/dist/api/workspace/index.d.ts +49 -2
  134. package/dist/api/workspace/index.d.ts.map +1 -1
  135. package/dist/errors/codes.d.ts +5 -8
  136. package/dist/errors/codes.d.ts.map +1 -1
  137. package/dist/handles.d.ts +32 -3
  138. package/dist/handles.d.ts.map +1 -1
  139. package/dist/index.cjs +6534 -2865
  140. package/dist/index.cjs.map +1 -1
  141. package/dist/index.d.ts +2 -0
  142. package/dist/index.d.ts.map +1 -1
  143. package/dist/index.js +6118 -2857
  144. package/dist/index.js.map +1 -1
  145. package/dist/massParameters.d.ts +287 -0
  146. package/dist/massParameters.d.ts.map +1 -0
  147. package/dist/massParameters.ops.d.ts +138 -0
  148. package/dist/massParameters.ops.d.ts.map +1 -0
  149. package/package.json +2 -1
  150. package/scripts/check-dist-fresh.mjs +22 -0
  151. package/scripts/generate-manifest.mjs +5 -0
  152. package/scripts/generate-manifest.test.mjs +14 -3
  153. package/src/api/core/camera/index.ts +429 -1
  154. package/src/api/core/geom/create/index.ts +1037 -102
  155. package/src/api/core/geom/query/brep.ts +60 -2
  156. package/src/api/core/geom/query/curve.ts +26 -2
  157. package/src/api/core/geom/query/edge.ts +2 -2
  158. package/src/api/core/geom/query/face.ts +109 -4
  159. package/src/api/core/geom/update/contour.ts +10 -2
  160. package/src/api/core/geom/update/profile.ts +2 -0
  161. package/src/api/core/handles/index.ts +3 -2
  162. package/src/api/core/index.ts +4 -4
  163. package/src/api/core/io/import/index.ts +11 -3
  164. package/src/api/core/layers.ts +380 -173
  165. package/src/api/core/mode/index.ts +19 -7
  166. package/src/api/core/proposals/index.ts +4 -3
  167. package/src/api/core/storeys/index.ts +19 -2
  168. package/src/api/core/storeys/layers.ts +339 -0
  169. package/src/api/core/tags.ts +76 -0
  170. package/src/api/core/zoom/index.ts +13 -0
  171. package/src/api/design/bim.ts +210 -0
  172. package/src/api/design/boolean/index.ts +2 -0
  173. package/src/api/design/catalog.ts +203 -0
  174. package/src/api/design/create/bulk-items.ts +294 -0
  175. package/src/api/design/create/grids.ts +137 -0
  176. package/src/api/design/create/index.ts +824 -141
  177. package/src/api/design/create/opening-fields.ts +40 -0
  178. package/src/api/design/delete/index.ts +6 -20
  179. package/src/api/design/dimensions.ts +453 -0
  180. package/src/api/design/doors/index.ts +64 -41
  181. package/src/api/design/family.ts +1342 -0
  182. package/src/api/design/grids.ts +237 -0
  183. package/src/api/design/index.ts +49 -4
  184. package/src/api/design/networks.ts +607 -0
  185. package/src/api/design/query/geometry/index.ts +35 -4
  186. package/src/api/design/query/grids.ts +197 -0
  187. package/src/api/design/query/index.ts +105 -5
  188. package/src/api/design/query/spaces.ts +0 -68
  189. package/src/api/design/types/index.ts +31 -24
  190. package/src/api/design/update/index.ts +398 -4
  191. package/src/api/design/windows/index.ts +40 -22
  192. package/src/api/entity/buildableEnvelope.ts +77 -2
  193. package/src/api/entity/referenceLine.ts +25 -12
  194. package/src/api/entity/space.ts +0 -2
  195. package/src/api/presentation/annotate.ts +90 -58
  196. package/src/api/presentation/camera.ts +289 -0
  197. package/src/api/presentation/drawingContract.ts +70 -0
  198. package/src/api/presentation/drawings.ts +1179 -0
  199. package/src/api/presentation/export.ts +32 -6
  200. package/src/api/presentation/graphics.ts +324 -0
  201. package/src/api/presentation/index.ts +73 -14
  202. package/src/api/presentation/placedViews.ts +120 -57
  203. package/src/api/presentation/sections.ts +420 -0
  204. package/src/api/presentation/sheets.ts +182 -37
  205. package/src/api/presentation/standards.ts +445 -0
  206. package/src/api/presentation/viewPresets.ts +241 -0
  207. package/src/api/presentation/views.ts +81 -10
  208. package/src/api/presentation/walkthroughs.ts +1201 -0
  209. package/src/api/program/departments.ts +54 -2
  210. package/src/api/program/index.ts +16 -6
  211. package/src/api/program/labels.ts +332 -0
  212. package/src/api/program/metadata.ts +364 -0
  213. package/src/api/program/spreadsheet.ts +282 -0
  214. package/src/api/workspace/index.ts +51 -2
  215. package/src/errors/codes.ts +9 -30
  216. package/src/handles.ts +42 -3
  217. package/src/index.ts +2 -0
  218. package/src/massParameters.ops.ts +246 -0
  219. package/src/massParameters.ts +427 -0
  220. package/test/drawingContract.test.mjs +288 -0
  221. package/test/errors.test.mjs +1 -4
  222. package/test/massParameters.test.mjs +952 -0
  223. package/test/paperPensContract.test.mjs +75 -0
  224. package/test/presentationViewSettings.test.mjs +85 -0
  225. package/api-manifest.full.json +0 -6928
  226. package/snaptrude-plugin-core-0.11.0.tgz +0 -0
@@ -1,13 +1,19 @@
1
1
  import * as z from "zod";
2
2
  import { PluginApiReturn } from "../../../types";
3
- import { BrepHandle, ComponentHandle, ContourHandle, ProfileHandle, Vec3Handle } from "../../../handles";
3
+ import { BrepHandle, ComponentHandle, ContourHandle, LineHandle, CurveHandle, ProfileHandle, Vec3Handle } from "../../../handles";
4
+ import { PluginGridStyleOptions } from "./grids";
4
5
  import { PluginSpaceType, PluginMassType, PluginDepartmentId } from "../../entity/space";
5
- import { PluginBuildableEnvelopePolygonVertex, PluginBuildableEnvelopeSetbackTier, PluginBuildableEnvelopeVerticalCap, PluginBuildableEnvelopeCreateResult } from "../../entity/buildableEnvelope";
6
+ import { PluginBuildableEnvelopePolygonVertex, PluginBuildableEnvelopeSetbackTier, PluginBuildableEnvelopeVerticalCap, PluginBuildableEnvelopeCreateResult, PluginDesignCreateBuildableEnvelopeFromSiteResult } from "../../entity/buildableEnvelope";
7
+ import type { PluginCreateDoorItem, PluginCreateFloorItem, PluginCreateFurnitureItem, PluginCreateVoidItem, PluginCreateWallRunItem, PluginCreateWindowItem } from "./bulk-items";
8
+ import { PluginWallTopProfile } from "./bulk-items";
9
+ import { PluginWallType } from "../types";
10
+ import { PluginFamilyPlacement, PluginFamilyFloorOptions, PluginFamilySlabOptions, PluginFamilyCeilingOptions, PluginFamilyValues } from "../catalog";
6
11
  /**
7
12
  * `design.create.*` — author new scene-committed BIM entities.
8
13
  *
9
14
  * Every creator takes geometry handles + scalars and returns a
10
- * {@linkcode ComponentHandle} (or `ComponentHandle[]` for plural creators) — the
15
+ * {@linkcode ComponentHandle} (or `ComponentHandle[]` for plural creators;
16
+ * `wallRuns` returns one `ComponentHandle[]` per run) — the
11
17
  * `Component.id` of the created entity, resolvable across the rest of the
12
18
  * `design.*` surface. Creation is an undoable host call; it **throws** on failure
13
19
  * (no `Result` wrapper — consistent with `core.geom.create.*`).
@@ -15,9 +21,17 @@ import { PluginBuildableEnvelopePolygonVertex, PluginBuildableEnvelopeSetbackTie
15
21
  * Footprint objects take a {@linkcode ContourHandle} (outer profile + holes);
16
22
  * build one with `snaptrude.core.geom.create.contourFromProfile(s)`.
17
23
  *
18
- * `door`/`window` place a catalog item into a host wall (the world point is
24
+ * Family overloads take `{ type, values? }` from `design.catalog`. The family supplies
25
+ * construction; the contour or axis supplies instance geometry. Geometry uses SU,
26
+ * while family length overrides use mm and angles use degrees. Omitted parameters
27
+ * retain family defaults; shared/type, formula and geometry-bound overrides are refused.
28
+ * Placement never publishes a definition. Unsupported references or geometry fail before mutation.
29
+ *
30
+ * `door`/`window` place a parametric family into a host wall (the world point is
19
31
  * projected onto the wall face to locate the opening; the wall is re-cut in one
20
- * undo entry) and throw if the point projects outside the wall. `smartLayout` is
32
+ * undo entry) and throw if the point projects outside the wall. Voids
33
+ * (`void`/`voids`) are the third hosted child: holes through slabs, floors,
34
+ * roofs and ceilings. `smartLayout` is
21
35
  * the one creator returning a grouped {@linkcode PluginSmartLayoutResult} rather
22
36
  * than a handle — it clones an in-scene template into one or more target spaces,
23
37
  * merging every target into a single undo batch (see its JSDoc).
@@ -148,6 +162,9 @@ export declare abstract class PluginDesignCreateApi {
148
162
  * Create a **slab** by extruding a footprint contour by `thickness`
149
163
  * (default direction: down).
150
164
  *
165
+ * To cut a hole in an EXISTING one, use `design.create.void`; a contour hole
166
+ * here is baked into the footprint.
167
+ *
151
168
  * @param contour - Footprint (outer + holes)
152
169
  * @param thickness - Slab thickness (> 0)
153
170
  * @param direction - Extrusion direction (default `"down"`)
@@ -168,31 +185,29 @@ export declare abstract class PluginDesignCreateApi {
168
185
  * const slab = await snaptrude.design.create.slab(contour, 0.15, "down", "Plinth")
169
186
  * ```
170
187
  */
171
- abstract slab(contour: ContourHandle, thickness: number, direction?: "up" | "down", slabType?: PluginSlabType): PluginApiReturn<ComponentHandle>;
188
+ abstract slab(...args: [
189
+ contour: ContourHandle,
190
+ thickness: number,
191
+ direction?: "up" | "down",
192
+ slabType?: PluginSlabType
193
+ ] | [contour: ContourHandle, options: PluginFamilySlabOptions]): PluginApiReturn<ComponentHandle>;
172
194
  /**
173
195
  * Create a **floor** by extruding a footprint contour by `thickness`
174
196
  * (extruded upward).
175
197
  *
176
- * The parametric engine owns floor topology and may resolve the request
177
- * differently than asked: drawing against existing floors can **split** the
178
- * footprint into several floors, or **merge** it into a pre-existing
179
- * neighbour (that floor's region grows; nothing new is created). The call
180
- * honors the engine's resolution and returns **every floor that covers the
181
- * requested footprint after the operation** — the newly created floor(s),
182
- * and/or the pre-existing floor that absorbed it. The array is never empty
183
- * on success; a lone independently-created floor comes back as `[floor]`.
198
+ * The native family overload takes `{ type, values?, position? }`. Contour
199
+ * geometry uses SU; family values use mm. The family supplies layer thickness.
200
+ * PG2 can split or merge the footprint, so both overloads return an array.
201
+ * A merge into an existing floor can return no newly created handles.
184
202
  *
185
- * **Breaking change in 0.11.0** — previously returned a single
186
- * {@linkcode ComponentHandle}; callers must switch to the array (the first
187
- * element preserves the old single-floor behavior for simple creates).
203
+ * To cut a hole in an EXISTING one, use `design.create.void`; a contour hole
204
+ * here is baked into the footprint.
188
205
  *
189
206
  * @param contour - Footprint (outer + holes)
190
207
  * @param thickness - Floor thickness (> 0)
191
208
  * @param position - Offset from origin
192
- * @returns the {@linkcode ComponentHandle}s of every floor covering the
193
- * requested footprint after parametric resolution (created and/or absorbing)
194
- * @throws if the contour is invalid, the thickness is not positive, or the
195
- * engine rejected the operation (nothing covers the footprint)
209
+ * @returns Newly created {@linkcode ComponentHandle}s; an empty array after a merge
210
+ * @throws if the contour is invalid or the thickness is not positive
196
211
  *
197
212
  * @examplePrompt Create a floor from this room outline
198
213
  * @examplePrompt Add a 100mm thick floor over the footprint
@@ -203,14 +218,58 @@ export declare abstract class PluginDesignCreateApi {
203
218
  * ```ts
204
219
  * const rect = await snaptrude.core.geom.create.profileRect(5, 4)
205
220
  * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)
206
- * const [floor, ...siblings] = await snaptrude.design.create.floor(contour, 0.1)
221
+ * const floor = await snaptrude.design.create.floor(contour, 0.1)
207
222
  * ```
223
+ *
224
+ * @performance For dimensional floors, `design.create.floors(items[])` uses one
225
+ * host round-trip and one undo entry. That bulk method does not accept native
226
+ * family options; use this method for a family-backed floor.
208
227
  */
209
- abstract floor(contour: ContourHandle, thickness: number, position?: Vec3Handle): PluginApiReturn<ComponentHandle[]>;
228
+ abstract floor(...args: [contour: ContourHandle, thickness: number, position?: Vec3Handle] | [contour: ContourHandle, options: PluginFamilyFloorOptions]): PluginApiReturn<ComponentHandle[]>;
229
+ /**
230
+ * Create **many floors** in one undoable operation (bulk plural of
231
+ * {@linkcode floor}). Each item extrudes its own footprint contour (outer
232
+ * profile + holes) upward by its own `thickness`, at its own optional
233
+ * position offset. Validate-all-or-throw; one command.
234
+ *
235
+ * @param items - One {@linkcode PluginCreateFloorItem} per floor to create
236
+ * (≥1, ≤1000)
237
+ * @returns the created floors as {@linkcode ComponentHandle}`[]`, in input order
238
+ * @throws `VALIDATION` if the items fail the schema (empty array, more than
239
+ * 1000 items, a non-positive thickness) or a contour is degenerate;
240
+ * `HANDLE_INVALID` if a `contour` or `position` handle is unknown or
241
+ * released; `OPERATION_FAILED` if extrusion fails (nothing is created —
242
+ * `details.itemIndex` is the failing item); `METHOD_NOT_PERMITTED` if the
243
+ * plugin may not write.
244
+ *
245
+ * @examplePrompt Create floors for all these room outlines at once
246
+ * @examplePrompt Add a floor to every space in one operation
247
+ * @examplePrompt Bulk create the floor plates for this building
248
+ * @examplePrompt Lay 100mm floors across these five footprints in one undo step
249
+ * @examplePrompt Create the ground and first floor slabs together
250
+ *
251
+ * @performance Bulk creator — the whole batch is ONE host round-trip and ONE undo
252
+ * entry. Always prefer this over calling `design.create.floor` in a loop: build the
253
+ * full `items[]` array first (all contours and offsets up front), then make one call.
254
+ *
255
+ * # Example
256
+ * ```ts
257
+ * const rect = await snaptrude.core.geom.create.profileRect(5, 4)
258
+ * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)
259
+ * const [ground, upper] = await snaptrude.design.create.floors([
260
+ * { contour, thickness: 0.1 },
261
+ * { contour, thickness: 0.1, position: await snaptrude.core.math.vec3.new(0, 3, 0) },
262
+ * ])
263
+ * ```
264
+ */
265
+ abstract floors(items: PluginCreateFloorItem[]): PluginApiReturn<ComponentHandle[]>;
210
266
  /**
211
267
  * Create a **roof** by extruding a footprint contour by `thickness`. Created
212
268
  * flat (extruded downward); pitch/slope is a separate post-creation edit.
213
269
  *
270
+ * To cut a hole in an EXISTING one, use `design.create.void`; a contour hole
271
+ * here is baked into the footprint.
272
+ *
214
273
  * @param contour - Footprint (outer + holes)
215
274
  * @param thickness - Roof-slab thickness (> 0)
216
275
  * @returns the {@linkcode ComponentHandle} of the created roof
@@ -228,11 +287,14 @@ export declare abstract class PluginDesignCreateApi {
228
287
  * const roof = await snaptrude.design.create.roof(contour, 0.2)
229
288
  * ```
230
289
  */
231
- abstract roof(contour: ContourHandle, thickness: number): PluginApiReturn<ComponentHandle>;
290
+ abstract roof(contour: ContourHandle, thickness: number | PluginFamilyPlacement): PluginApiReturn<ComponentHandle>;
232
291
  /**
233
292
  * Create a **ceiling** by extruding a footprint contour by `thickness`, lifted
234
293
  * `heightFromFloor` above the floor.
235
294
  *
295
+ * To cut a hole in an EXISTING one, use `design.create.void`; a contour hole
296
+ * here is baked into the footprint.
297
+ *
236
298
  * @param contour - Footprint (outer + holes)
237
299
  * @param thickness - Ceiling thickness (> 0)
238
300
  * @param heightFromFloor - Lift above the floor (default 0)
@@ -251,7 +313,7 @@ export declare abstract class PluginDesignCreateApi {
251
313
  * const ceiling = await snaptrude.design.create.ceiling(contour, 0.05, 2.8)
252
314
  * ```
253
315
  */
254
- abstract ceiling(contour: ContourHandle, thickness: number, heightFromFloor?: number): PluginApiReturn<ComponentHandle>;
316
+ abstract ceiling(...args: [contour: ContourHandle, thickness: number, heightFromFloor?: number] | [contour: ContourHandle, options: PluginFamilyCeilingOptions]): PluginApiReturn<ComponentHandle>;
255
317
  /**
256
318
  * Create a **column** by extruding a cross-section contour upward by `height`
257
319
  * from a base `position`. The column is built to EXACTLY `height` — unlike
@@ -279,7 +341,12 @@ export declare abstract class PluginDesignCreateApi {
279
341
  * const column = await snaptrude.design.create.column(base, crossSection, 3)
280
342
  * ```
281
343
  */
282
- abstract column(position: Vec3Handle, crossSection: ContourHandle, height: number, directionUp?: Vec3Handle): PluginApiReturn<ComponentHandle>;
344
+ abstract column(...args: [
345
+ position: Vec3Handle,
346
+ crossSection: ContourHandle,
347
+ height: number,
348
+ directionUp?: Vec3Handle
349
+ ] | [axis: LineHandle, options: PluginFamilyPlacement]): PluginApiReturn<ComponentHandle>;
283
350
  /**
284
351
  * Create a **beam** by extruding a cross-section contour along `direction` by
285
352
  * `length`. Matches the Snaptrude beam tool's semantics: the beam body hangs
@@ -320,7 +387,7 @@ export declare abstract class PluginDesignCreateApi {
320
387
  * const beam = await snaptrude.design.create.beam(section, 6, alongX)
321
388
  * ```
322
389
  */
323
- abstract beam(section: ContourHandle, length: number, direction?: Vec3Handle): PluginApiReturn<ComponentHandle>;
390
+ abstract beam(...args: [section: ContourHandle, length: number, direction?: Vec3Handle] | [axis: LineHandle, options: PluginFamilyPlacement]): PluginApiReturn<ComponentHandle>;
324
391
  /**
325
392
  * Create a connected run of **walls** from a profile — one wall per curve in
326
393
  * the profile's chain, with mitred corners at shared endpoints.
@@ -329,27 +396,27 @@ export declare abstract class PluginDesignCreateApi {
329
396
  * @param height - Wall height (default engine default)
330
397
  * @param thickness - Wall thickness (default: the `wallType`'s total layer
331
398
  * thickness when `wallType` is given, else the engine default)
332
- * @param wallType - Wall type to build with — the same searchable list the
333
- * Draw tab's Wall Type dropdown offers. Pass a name from
334
- * `design.types.list("wall")` (the summary's `label`, or its `"wall:…"` id).
335
- * Drives the wall's construction layers and default material, and — when
336
- * `thickness` is omitted — its total layer thickness. Default: the engine's
337
- * generic wall.
399
+ * @param wallType - Legacy label/`wall:` id, or the exact `nativeFamily`
400
+ * `{ id, version }` pin from `design.types.list("wall")`. Native pins are
401
+ * authorized on every use; selecting a family in Draw is not registration.
402
+ * Native pins support straight horizontal centerlines and flat tops only.
403
+ * Omit thickness for native pins; a conflicting explicit thickness rejects.
404
+ * Default: the engine's generic wall.
338
405
  * @param storey - Target storey (integer: `1` ground, `2` first floor, `-1`
339
406
  * basement — same convention as `design.create.space`). The walls are
340
407
  * assigned to it and lifted to its base elevation, all inside the same
341
408
  * single undo entry. The storey must already exist
342
409
  * (`core.storeys.create` first). Default: geometry-derived — a profile
343
410
  * drawn at y = 0 lands on storey 1; the ACTIVE storey is NOT consulted.
344
- * @returns the actually-created wall {@linkcode ComponentHandle}s. The
345
- * parametric engine owns wall topology — curves touching existing walls
346
- * may merge into or split against them, so the returned count can differ
347
- * from the input curve count. Profile-ordered 1:1 matches come first,
348
- * then the remaining merged/split products in creation order. Re-query
349
- * (e.g. `design.query.spaces.listGeneratedBim`) rather than assuming a
350
- * wall per input curve.
411
+ * @param topProfiles - Optional top edge per curve of `profile` (same order):
412
+ * a {@linkcode PluginWallTopProfile} makes that wall raked / gabled; `null`
413
+ * or a missing entry keeps it flat at `height`. Straight curves only. Such
414
+ * walls are non-parametric (see {@linkcode PluginWallTopProfile}).
415
+ * @returns a {@linkcode ComponentHandle}`[]` (one per wall), in profile order
351
416
  * @throws if the profile is empty, `wallType` names no wall type in the
352
- * project, `storey` does not exist, or wall creation fails
417
+ * project, `storey` does not exist, `topProfiles` has more entries than the
418
+ * profile has curves or names an arc curve, a top profile drops to the wall
419
+ * base at a mitred corner, or wall creation fails
353
420
  *
354
421
  * @examplePrompt Draw walls along this centerline
355
422
  * @examplePrompt Create 3m high, 200mm thick walls from these points
@@ -358,6 +425,9 @@ export declare abstract class PluginDesignCreateApi {
358
425
  * @examplePrompt Add walls with mitred corners along the path
359
426
  * @examplePrompt Draw brick walls with plaster along this outline
360
427
  * @examplePrompt Build the perimeter in exposed concrete walls
428
+ * @examplePrompt Create a raked wall that slopes from 3m to 5m
429
+ * @examplePrompt Build a gable end wall with the ridge in the middle
430
+ * @examplePrompt Draw a wall with a sloped top edge
361
431
  *
362
432
  * # Example
363
433
  * ```ts
@@ -373,9 +443,77 @@ export declare abstract class PluginDesignCreateApi {
373
443
  * const brickWalls = await snaptrude.design.create.walls(
374
444
  * centerlines, 3, undefined, brick.label,
375
445
  * )
446
+ * // …a raked wall (3m at the start, 5m at the end) on a single centerline:
447
+ * const run = await snaptrude.core.geom.create.profileFromCurves([
448
+ * await snaptrude.core.geom.create.line(await v.new(0, 0, 10), await v.new(8, 0, 10)),
449
+ * ])
450
+ * const [raked] = await snaptrude.design.create.walls(run, undefined, 0.2, undefined, undefined, [
451
+ * [{ along: 0, height: 3 }, { along: 1, height: 5 }],
452
+ * ])
376
453
  * ```
454
+ *
455
+ * @performance For MORE THAN ONE run, call `design.create.wallRuns(items[])` — one
456
+ * host round-trip and ONE undo entry for every run in the batch. Looping this
457
+ * single-run creator is N round-trips and N undo entries.
377
458
  */
378
- abstract walls(profile: ProfileHandle, height?: number, thickness?: number, wallType?: string, storey?: number): PluginApiReturn<ComponentHandle[]>;
459
+ abstract walls(profile: ProfileHandle, height?: number, thickness?: number, wallType?: PluginWallType, storey?: number, topProfiles?: (PluginWallTopProfile | null)[], values?: PluginFamilyValues): PluginApiReturn<ComponentHandle[]>;
460
+ /**
461
+ * Create **many wall runs** in one undoable operation (bulk plural of
462
+ * {@linkcode walls}). Each item is one full run — a wall per curve in that
463
+ * item's profile chain, mitred at shared endpoints. Junctions resolve within a
464
+ * run, not between runs. Each item carries its own
465
+ * dimensions, `wallType` and `storey`, so a single call can build a whole
466
+ * floor plate or several storeys at once. Per-curve `topProfiles` make raked
467
+ * or gabled walls (see {@linkcode PluginWallTopProfile}). Validate-all-or-throw;
468
+ * one command.
469
+ *
470
+ * @param items - One {@linkcode PluginCreateWallRunItem} per run to create
471
+ * (≥1, ≤1000)
472
+ * @returns one {@linkcode ComponentHandle}`[]` per item, in input order —
473
+ * each inner array holding that run's walls in profile-curve order
474
+ * @throws `VALIDATION` if the items fail the schema (empty array, more than
475
+ * 1000 items, a non-positive height or thickness, a zero-length curve);
476
+ * `HANDLE_INVALID` if a `profile` handle is unknown or released;
477
+ * `PRECONDITION_FAILED` if a profile has no curves, `wallType` names no
478
+ * wall type in the project, or `storey` does not exist;
479
+ * `OPERATION_FAILED` if wall creation fails (nothing is created —
480
+ * `details.itemIndex` is the failing item); `METHOD_NOT_PERMITTED` if the
481
+ * plugin may not write.
482
+ *
483
+ * @examplePrompt Draw all the walls of this floor plan at once
484
+ * @examplePrompt Build every room's perimeter in one operation
485
+ * @examplePrompt Bulk create wall runs from these centerlines
486
+ * @examplePrompt Create the walls for both storeys in a single undo step
487
+ * @examplePrompt Turn these polylines into 200mm brick walls together
488
+ * @examplePrompt Import these raked walls with their top profiles in one go
489
+ *
490
+ * @performance Bulk creator — the whole batch is ONE host round-trip and ONE undo
491
+ * entry. Always prefer this over calling `design.create.walls` in a loop: build the
492
+ * full `items[]` array first (all profiles up front), then make one call.
493
+ *
494
+ * # Example
495
+ * ```ts
496
+ * const v = snaptrude.core.math.vec3
497
+ * const ground = await snaptrude.core.geom.create.profileFromLinePoints([
498
+ * await v.new(0, 0, 0),
499
+ * await v.new(8, 0, 0),
500
+ * await v.new(8, 0, 6),
501
+ * ])
502
+ * const upper = await snaptrude.core.geom.create.profileFromLinePoints([
503
+ * await v.new(0, 0, 0),
504
+ * await v.new(8, 0, 0),
505
+ * ])
506
+ * const [groundWalls, upperWalls] = await snaptrude.design.create.wallRuns([
507
+ * { profile: ground, height: 3, thickness: 0.2 },
508
+ * { profile: upper, height: 3, storey: 2 },
509
+ * // one gable wall: 3m at both ends, 5m ridge in the middle
510
+ * { profile: upper, thickness: 0.2, storey: 3,
511
+ * topProfiles: [[{ along: 0, height: 3 }, { along: 0.5, height: 5 }, { along: 1, height: 3 }]] },
512
+ * ])
513
+ * console.log(groundWalls.length, "walls on the ground floor")
514
+ * ```
515
+ */
516
+ abstract wallRuns(items: PluginCreateWallRunItem[]): PluginApiReturn<ComponentHandle[][]>;
379
517
  /**
380
518
  * Create a **staircase** from a parametric preset, placed at a point.
381
519
  *
@@ -418,8 +556,14 @@ export declare abstract class PluginDesignCreateApi {
418
556
  * every created line.
419
557
  *
420
558
  * @param profile - Ordered curve chain (centerlines)
421
- * @param color - Hex color `"#RRGGBB"` (default white)
422
- * @param thickness - Line thickness (default 1)
559
+ * Prefer `{ styleId: "wide" }`: the project style's pen/pattern and native
560
+ * legacy mirror are saved in the creation command, as one undo step. styleId
561
+ * requires Paper Pens; unstyled legacy creation works with the feature off.
562
+ * Do not mix options with trailing positional arguments, or styleId with
563
+ * legacy thickness/style. The old positional signature remains supported.
564
+ *
565
+ * @param colorOrOptions - Options, or legacy hex color `"#RRGGBB"`.
566
+ * @param thickness - Legacy line thickness (default 1)
423
567
  * @param style - Line style (default `SOLID`)
424
568
  * @param gridTag - Grid tag label (default `"A"`)
425
569
  * @returns a {@linkcode ComponentHandle}`[]` (one per curve), in profile order
@@ -446,7 +590,113 @@ export declare abstract class PluginDesignCreateApi {
446
590
  * )
447
591
  * ```
448
592
  */
449
- abstract referenceLines(profile: ProfileHandle, color?: string, thickness?: number, style?: PluginReferenceLineStyle, gridTag?: string): PluginApiReturn<ComponentHandle[]>;
593
+ abstract referenceLines(profile: ProfileHandle, colorOrOptions?: string | PluginReferenceLineOptions, thickness?: number, style?: PluginReferenceLineStyle, gridTag?: string): PluginApiReturn<ComponentHandle[]>;
594
+ /**
595
+ * Create a free rectangular **structural grid** — one grid group with two
596
+ * perpendicular line families (`linesX` lines spaced `spacingX` apart, and
597
+ * `linesY` lines spaced `spacingY` apart) on the active storey. One undoable
598
+ * creation.
599
+ *
600
+ * Units: spacings in Snaptrude units; `angle` in degrees (CCW about +Y,
601
+ * default 0). Without `center` the grid is centred on the current viewport
602
+ * (the native tool's behavior) — pass `center` for deterministic placement.
603
+ *
604
+ * @param linesX - Line count of the first family (integer ≥ 1)
605
+ * @param linesY - Line count of the second family (integer ≥ 1)
606
+ * @param spacingX - First-family spacing (Snaptrude units, > 0)
607
+ * @param spacingY - Second-family spacing (Snaptrude units, > 0)
608
+ * @param options - `angle`, `center`, and {@linkcode PluginGridStyleOptions}
609
+ * @returns the created grid group's {@linkcode ComponentHandle}
610
+ *
611
+ * @examplePrompt Create a 5 by 8 structural grid with 6 metre spacing
612
+ * @examplePrompt Add a column grid rotated 30 degrees
613
+ * @examplePrompt Set up a structural grid at the site origin
614
+ *
615
+ * # Example
616
+ * ```ts
617
+ * const centre = await snaptrude.core.math.vec3.new(0, 0, 0)
618
+ * const grid = await snaptrude.design.create.grid(5, 8, 6, 6, { center: centre })
619
+ * ```
620
+ */
621
+ abstract grid(linesX: number, linesY: number, spacingX: number, spacingY: number, options?: {
622
+ angle?: number;
623
+ center?: Vec3Handle;
624
+ } & PluginGridStyleOptions): PluginApiReturn<ComponentHandle>;
625
+ /**
626
+ * Create a **structural grid from a single curve** — one grid group holding
627
+ * one wing with one line (the draw tool's output). The curve may be a line
628
+ * or an arc; circles are rejected with `VALIDATION`. Undoable.
629
+ *
630
+ * @param curve - The grid line's geometry ({@linkcode CurveHandle}, world space)
631
+ * @param options - `tag` (defaults to the draw tool's next tag) and
632
+ * {@linkcode PluginGridStyleOptions}
633
+ * @returns the created grid group's {@linkcode ComponentHandle}
634
+ *
635
+ * @examplePrompt Draw a grid line from A to B
636
+ * @examplePrompt Add a curved grid line through these points
637
+ * @examplePrompt Create grid line "C" along this wall
638
+ *
639
+ * # Example
640
+ * ```ts
641
+ * const { vec3 } = snaptrude.core.math
642
+ * const from = await vec3.new(0, 0, 0)
643
+ * const to = await vec3.new(30, 0, 0)
644
+ * const curve = await snaptrude.core.geom.create.line(from, to)
645
+ * const grid = await snaptrude.design.create.gridFromCurve(curve, { tag: "A" })
646
+ * ```
647
+ */
648
+ abstract gridFromCurve(curve: CurveHandle, options?: {
649
+ tag?: string;
650
+ } & PluginGridStyleOptions): PluginApiReturn<ComponentHandle>;
651
+ /**
652
+ * Generate **structural grids fitted to mass footprints** — one grid group
653
+ * per footprint cluster, with counts and orientation derived from each
654
+ * footprint's geometry and the given spacings. All created groups commit as
655
+ * ONE undoable unit.
656
+ *
657
+ * Lenient like the native tool: masses without an extractable footprint
658
+ * (no B-rep, degenerate top face) are skipped; throws `VALIDATION` only when
659
+ * NONE of the given masses yields a footprint.
660
+ *
661
+ * @param masses - Masses whose footprints seat the grids
662
+ * @param spacingX - First-family spacing (Snaptrude units, > 0)
663
+ * @param spacingY - Second-family spacing (Snaptrude units, > 0)
664
+ * @param options - {@linkcode PluginGridStyleOptions}
665
+ * @returns the created grid groups' {@linkcode ComponentHandle}`[]`
666
+ *
667
+ * @examplePrompt Generate grids for the selected masses
668
+ * @examplePrompt Auto-generate a 6m structural grid on this building
669
+ * @examplePrompt Fit column grids to every mass on this storey
670
+ *
671
+ * # Example
672
+ * ```ts
673
+ * const masses = await snaptrude.design.query.listMasses({ storeys: [1] })
674
+ * const grids = await snaptrude.design.create.gridsFromMasses(masses, 6, 6)
675
+ * ```
676
+ */
677
+ abstract gridsFromMasses(masses: ComponentHandle[], spacingX: number, spacingY: number, options?: PluginGridStyleOptions): PluginApiReturn<ComponentHandle[]>;
678
+ /**
679
+ * Create **columns at every grid-line intersection** of the given grid
680
+ * groups, sized `width` × `depth` and oriented to the grid axes, on the
681
+ * grids' storey. All columns commit as ONE undoable unit.
682
+ *
683
+ * @param grids - Grid groups whose intersections seat the columns
684
+ * @param width - Column width (Snaptrude units, > 0)
685
+ * @param depth - Column depth (Snaptrude units, > 0)
686
+ * @returns the created columns' {@linkcode ComponentHandle}`[]`
687
+ * @throws `VALIDATION` when an id does not resolve to a grid group;
688
+ * `OPERATION_FAILED` when the grids have no line intersections
689
+ *
690
+ * @examplePrompt Generate columns on this grid
691
+ * @examplePrompt Place 450mm square columns at every grid intersection
692
+ *
693
+ * # Example
694
+ * ```ts
695
+ * const grids = await snaptrude.design.query.listGrids()
696
+ * const columns = await snaptrude.design.create.columnsFromGrids(grids, 0.45, 0.45)
697
+ * ```
698
+ */
699
+ abstract columnsFromGrids(grids: ComponentHandle[], width: number, depth: number): PluginApiReturn<ComponentHandle[]>;
450
700
  /**
451
701
  * Place a **furniture** item from the project library at a world position.
452
702
  *
@@ -465,17 +715,19 @@ export declare abstract class PluginDesignCreateApi {
465
715
  * `position.y` (the same surface-flush contract as interactive drag-drop) —
466
716
  * pass the floor/storey elevation to stand furniture on it; never add half
467
717
  * the item's height yourself.
468
- * @param options - Optional placement options: `label` — instance name
469
- * (default auto `${name}Ins${n}`); `createNewSourceMesh` — emit a
470
- * source-mesh creation command (default `true`). `position.y` is always
471
- * grounded: the placed instance's bounding-box bottom rests at it (the
472
- * surface-flush grounding described above)
718
+ * @param options - Optional placement options: `label` — instance name and
719
+ * readable label (`design.query.getLabel`; default auto `${name}Ins${n}`);
720
+ * `createNewSourceMesh` — legacy flag, kept for compatibility. The host owns
721
+ * source-mesh persistence: a catalog source is recorded exactly once, by the
722
+ * first placement that brings it in, and this flag cannot skip that record.
473
723
  * @param angleInDegrees - Optional signed rotation about the vertical axis, in
474
724
  * degrees (same convention as {@linkcode PluginDesignTransformApi.rotate}).
475
725
  * Applied at creation time so it is part of the placement's single undo entry.
476
726
  * Default: the item's own (unrotated) orientation.
477
727
  * @returns the {@linkcode ComponentHandle} of the placed furniture instance
478
- * @throws if the catalog id is unknown, the source mesh fails to load, or placement fails
728
+ * @throws if the catalog id is unknown, the source mesh fails to load, or placement fails;
729
+ * `PRECONDITION_FAILED` (`details.engineCode: "TOOL_ACTIVE"`) while the interactive
730
+ * furniture tool is active — finish or cancel it first
479
731
  *
480
732
  * @examplePrompt Place a chair from the library at this spot
481
733
  * @examplePrompt Add a sofa from the furniture catalog to the living room
@@ -499,33 +751,76 @@ export declare abstract class PluginDesignCreateApi {
499
751
  * 90,
500
752
  * )
501
753
  * ```
754
+ *
755
+ * @performance For MORE THAN ONE item, call `design.create.furnitureItems(items[])` —
756
+ * one host round-trip and ONE undo entry, and a catalog source shared by several
757
+ * items is fetched once. Looping this single-item creator is N round-trips.
502
758
  */
503
759
  abstract furniture(catalogId: string, position: Vec3Handle, options?: {
504
760
  label?: string;
505
761
  createNewSourceMesh?: boolean;
506
762
  }, angleInDegrees?: number): PluginApiReturn<ComponentHandle>;
507
763
  /**
508
- * Place a **door** from the catalog into a host wall.
764
+ * Place **many furniture items** in one undoable operation (bulk plural of
765
+ * {@linkcode furniture}). Each item names a catalog id and an absolute world
766
+ * position (`position.y` is the REST elevation — the same grounding contract
767
+ * as the singular creator), with optional label and rotation. A catalog
768
+ * source shared by several items is fetched and recorded once for the whole
769
+ * batch, so the host — not the caller — owns source persistence (there is no
770
+ * per-item `createNewSourceMesh`). Validate-all-or-throw; one command.
771
+ *
772
+ * @param items - One {@linkcode PluginCreateFurnitureItem} per instance to
773
+ * place (≥1, ≤1000)
774
+ * @returns the placed instances as {@linkcode ComponentHandle}`[]`, in input order
775
+ * @throws `VALIDATION` if the items fail the schema (empty array, more than
776
+ * 1000 items); `HANDLE_INVALID` if a `position` handle is unknown or
777
+ * released; `PRECONDITION_FAILED` if a catalog id is unknown, a furniture
778
+ * tool is active, or a parametric group is active (exit it first, or place
779
+ * items one at a time with `furniture`); `OPERATION_FAILED` if a source
780
+ * mesh fails to load or placement fails (nothing is created —
781
+ * `details.itemIndex` is the failing item); `METHOD_NOT_PERMITTED` if the plugin may not write.
782
+ *
783
+ * @examplePrompt Place all the desks for this office at once
784
+ * @examplePrompt Furnish every bedroom in one operation
785
+ * @examplePrompt Bulk place these chairs around the table
786
+ * @examplePrompt Add the whole furniture layout in a single undo step
787
+ * @examplePrompt Drop twenty copies of this chair at these positions
788
+ *
789
+ * @performance Bulk creator — the whole batch is ONE host round-trip and ONE undo
790
+ * entry, and each distinct catalog source loads once. Always prefer this over
791
+ * calling `design.create.furniture` in a loop: build the full `items[]` array
792
+ * first (all positions and angles up front), then make one call.
793
+ *
794
+ * # Example
795
+ * ```ts
796
+ * const v = snaptrude.core.math.vec3
797
+ * const [chair] = await snaptrude.design.furniture.listCatalog()
798
+ * const placed = await snaptrude.design.create.furnitureItems([
799
+ * { catalogId: chair.id, position: await v.new(3, 0, 5), label: "Chair-01" },
800
+ * { catalogId: chair.id, position: await v.new(4, 0, 5), angleInDegrees: 90 },
801
+ * { catalogId: chair.id, position: await v.new(5, 0, 5), angleInDegrees: 180 },
802
+ * ])
803
+ * ```
804
+ */
805
+ abstract furnitureItems(items: PluginCreateFurnitureItem[]): PluginApiReturn<ComponentHandle[]>;
806
+ /**
807
+ * Place a parametric **door** family into a host wall.
509
808
  *
510
- * Identified by a **catalog (library) id** — the team object's stable `_id`
511
- * or the general library's `fullName`. Discover ids with
809
+ * Identified by a saved **family definition id**. Discover ids with
512
810
  * {@linkcode PluginDesignDoorsApi.listCatalog}. The world `position` is
513
811
  * projected onto the host wall's face to locate the opening; the wall is
514
812
  * re-cut and the door hosted in a single undo entry. Placement is
515
- * asynchronous (the source mesh is fetched if not cached).
813
+ * asynchronous. Values and host bindings are evaluated before the first cut.
516
814
  *
517
- * @param catalogId - Library id: team `_id` or general `fullName`
815
+ * @param familyId - Hosted door definition ID; legacy mesh catalog IDs are not accepted
518
816
  * @param hostWall - The wall to host the door
519
817
  * @param position - World point projected onto the wall to locate the opening
520
- * @param options - Optional placement options: `label` — instance name
521
- * @param facing - World point selecting which side of the wall the door faces
522
- * (the room it opens into) — the same convention as approaching the wall
523
- * from that side with the cursor in the interactive tool. Any point clearly
524
- * on that side works (e.g. the room's center). Default: the engine picks a
525
- * side (nondeterministic when `position` sits on the wall centerline).
818
+ * @param options - `version` pins the definition. `values` sets authored parameters
819
+ * (numeric lengths in SU, or unit strings). `label` names the instance.
820
+ * `hinge` selects the declared `hand` enum: local -X is left, +X is right.
821
+ * @param facing - World point selecting local +Z; omitted uses the picked face
526
822
  * @returns the {@linkcode ComponentHandle} of the placed door
527
- * @throws if the catalog id is unknown, the host is not a wall, the source
528
- * mesh fails to load, or the projected point falls **outside** the host wall
823
+ * @throws if the family/category/parameters are invalid, or placement or cutting fails
529
824
  *
530
825
  * @examplePrompt Add a door to this wall here
531
826
  * @examplePrompt Place a sliding door on the selected wall
@@ -533,6 +828,7 @@ export declare abstract class PluginDesignCreateApi {
533
828
  * @examplePrompt Insert the entrance door into this wall
534
829
  * @examplePrompt Add a door to the wall and call it Entry-01
535
830
  * @examplePrompt Add a door that opens into the living room
831
+ * @examplePrompt Put a door here hinged on the north jamb
536
832
  *
537
833
  * # Example
538
834
  * ```ts
@@ -552,32 +848,90 @@ export declare abstract class PluginDesignCreateApi {
552
848
  * undefined,
553
849
  * await snaptrude.core.math.vec3.new(3, 0, 9),
554
850
  * )
851
+ * // …and hinged on the jamb nearest a point (here the +x end of the opening):
852
+ * const hingedRight = await snaptrude.design.create.door(
853
+ * entry.id,
854
+ * wall,
855
+ * await snaptrude.core.math.vec3.new(3, 0, 5),
856
+ * { hinge: await snaptrude.core.math.vec3.new(3.5, 0, 5) },
857
+ * await snaptrude.core.math.vec3.new(3, 0, 9),
858
+ * )
555
859
  * ```
860
+ *
861
+ * @performance For MORE THAN ONE door, call `design.create.doors(items[])` — one host
862
+ * round-trip and ONE undo entry, with each host wall re-cut once per opening inside
863
+ * that single call. Looping this single-door creator is N round-trips.
556
864
  */
557
- abstract door(catalogId: string, hostWall: ComponentHandle, position: Vec3Handle, options?: {
865
+ abstract door(familyId: string, hostWall: ComponentHandle, position: Vec3Handle, options?: {
558
866
  label?: string;
867
+ hinge?: Vec3Handle;
868
+ version?: number;
869
+ values?: Record<string, number | string>;
559
870
  }, facing?: Vec3Handle): PluginApiReturn<ComponentHandle>;
560
871
  /**
561
- * Place a **window** from the catalog into a host wall.
872
+ * Place **many doors** into host walls in one undoable operation (bulk plural
873
+ * of {@linkcode door}). Each item carries its own family id, host wall,
874
+ * world position, and optional `facing`, `label`, `width` and `height` — the
875
+ * same fields as a `"door"` {@linkcode PluginDesignCreateOpeningOptions}.
876
+ * Validate-all-or-throw; one command.
877
+ *
878
+ * The wall keeps its identity. Several items may use the same host.
879
+ * Width and height set named recipe parameters, not mesh scale. The recipe's
880
+ * evaluated hole can include frame allowances. A failed item rolls back the batch.
881
+ *
882
+ * @param items - One {@linkcode PluginCreateDoorItem} per door to place
883
+ * (≥1, ≤1000)
884
+ * @returns the placed doors as {@linkcode ComponentHandle}`[]`, in input order
885
+ * @throws `VALIDATION` if the items fail the schema (empty array, more than
886
+ * 1000 items, unknown fields, a non-positive `width`/`height`);
887
+ * `HANDLE_INVALID` if a `position`, `facing` or `hinge` handle is unknown
888
+ * or released; `PRECONDITION_FAILED` if the family cannot be resolved or saved,
889
+ * or a host is locked / is not in the active proposal;
890
+ * `OPERATION_FAILED` if placement, containment, overlap checks or cutting fail
891
+ * (nothing is created — `details.itemIndex` is the failing item);
892
+ * `METHOD_NOT_PERMITTED` if the plugin may not write.
893
+ *
894
+ * @examplePrompt Add doors to all of these walls at once
895
+ * @examplePrompt Place a door in every room in one operation
896
+ * @examplePrompt Bulk add the entrance doors from this schedule
897
+ * @examplePrompt Put three doors on this wall in a single undo step
898
+ * @examplePrompt Add all the doors for this floor plan together
899
+ *
900
+ * @performance Bulk creator — the whole batch is ONE host round-trip and ONE undo
901
+ * entry. Always prefer this over
902
+ * calling `design.create.door` in a loop: build the full `items[]` array first
903
+ * (all host walls and points up front), then make one call.
562
904
  *
563
- * Identified by a **catalog (library) id** — the team object's stable `_id`
564
- * or the general library's `fullName`. Discover ids with
905
+ * # Example
906
+ * ```ts
907
+ * const v = snaptrude.core.math.vec3
908
+ * const [wall] = await snaptrude.design.query.listWalls({ isSelected: true })
909
+ * const [entry] = await snaptrude.design.doors.listCatalog()
910
+ * const [front, side] = await snaptrude.design.create.doors([
911
+ * { familyId: entry.id, hostWall: wall, position: await v.new(2, 0, 5), label: "D-01" },
912
+ * { familyId: entry.id, hostWall: wall, position: await v.new(6, 0, 5), values: { width: "1200mm" } },
913
+ * ])
914
+ * // The host still resolves after both cuts:
915
+ * const currentWall = await snaptrude.design.query.getHost(front)
916
+ * ```
917
+ */
918
+ abstract doors(items: PluginCreateDoorItem[]): PluginApiReturn<ComponentHandle[]>;
919
+ /**
920
+ * Place a parametric **window** family into a host wall.
921
+ *
922
+ * Identified by a saved **family definition id**. Discover ids with
565
923
  * {@linkcode PluginDesignWindowsApi.listCatalog}. The world `position` is
566
924
  * projected onto the host wall's face to locate the opening; the wall is
567
925
  * re-cut and the window hosted in a single undo entry. Placement is
568
- * asynchronous (the source mesh is fetched if not cached).
926
+ * asynchronous. The sill parameter determines elevation; position Y is ignored.
569
927
  *
570
- * @param catalogId - Library id: team `_id` or general `fullName`
928
+ * @param familyId - Hosted window definition ID; legacy mesh catalog IDs are not accepted
571
929
  * @param hostWall - The wall to host the window
572
930
  * @param position - World point projected onto the wall to locate the opening
573
- * @param options - Optional placement options: `label` — instance name
574
- * @param facing - World point selecting which side of the wall the window
575
- * faces (matters for asymmetric windows, e.g. casement swing) — same
576
- * convention as {@linkcode PluginDesignCreateApi.door}. Default: the engine
577
- * picks a side (nondeterministic when `position` sits on the centerline).
931
+ * @param options - `version`, `values`, `label`, and parameter-driven `hinge`, as for door
932
+ * @param facing - World point selecting local +Z; omitted uses the picked face
578
933
  * @returns the {@linkcode ComponentHandle} of the placed window
579
- * @throws if the catalog id is unknown, the host is not a wall, the source
580
- * mesh fails to load, or the projected point falls **outside** the host wall
934
+ * @throws if the family/category/parameters are invalid, or placement or cutting fails
581
935
  *
582
936
  * @examplePrompt Add a window to this wall here
583
937
  * @examplePrompt Place a casement window on the selected wall
@@ -597,35 +951,227 @@ export declare abstract class PluginDesignCreateApi {
597
951
  * { label: "Win-01" },
598
952
  * )
599
953
  * ```
954
+ *
955
+ * @performance For MORE THAN ONE window, call `design.create.windows(items[])` — one
956
+ * host round-trip and ONE undo entry, with each host wall re-cut once per opening
957
+ * inside that single call. Looping this single-window creator is N round-trips.
600
958
  */
601
- abstract window(catalogId: string, hostWall: ComponentHandle, position: Vec3Handle, options?: {
959
+ abstract window(familyId: string, hostWall: ComponentHandle, position: Vec3Handle, options?: {
602
960
  label?: string;
961
+ hinge?: Vec3Handle;
962
+ version?: number;
963
+ values?: Record<string, number | string>;
603
964
  }, facing?: Vec3Handle): PluginApiReturn<ComponentHandle>;
604
965
  /**
605
- * Place a catalog **door or window** into a host wall with optional size overrides.
966
+ * Place **many windows** into host walls in one undoable operation (bulk
967
+ * plural of {@linkcode window}). Each item carries its own family id, host
968
+ * wall, world position, and optional `facing`, `label`, `width`, `height` and
969
+ * `sillHeight` — the same fields as a `"window"`
970
+ * {@linkcode PluginDesignCreateOpeningOptions}. `sillHeight` is measured from
971
+ * the host wall base to the BOTTOM of the window. Validate-all-or-throw; one
972
+ * command.
973
+ *
974
+ * Hosts keep their identity. Width, height and sillHeight set the declared
975
+ * width, height and sill parameters before the first cut. No mesh scaling occurs.
976
+ *
977
+ * @param items - One {@linkcode PluginCreateWindowItem} per window to place
978
+ * (≥1, ≤1000)
979
+ * @returns the placed windows as {@linkcode ComponentHandle}`[]`, in input order
980
+ * @throws `VALIDATION` if the items fail the schema (empty array, more than
981
+ * 1000 items, unknown fields, a non-positive `width`/`height`, a negative
982
+ * `sillHeight`); `HANDLE_INVALID` if a `position`, `facing` or `hinge`
983
+ * handle is unknown or released; `PRECONDITION_FAILED` if the family cannot be
984
+ * resolved or saved, or a host is locked / is not in the active proposal;
985
+ * `OPERATION_FAILED` if placement, containment, overlap checks or cutting fail
986
+ * (nothing is created — `details.itemIndex` is the failing item);
987
+ * `METHOD_NOT_PERMITTED` if the plugin may not write.
988
+ *
989
+ * @examplePrompt Add windows along this whole facade at once
990
+ * @examplePrompt Place a window in every bedroom in one operation
991
+ * @examplePrompt Bulk add the windows from this schedule
992
+ * @examplePrompt Put four windows on this wall in a single undo step
993
+ * @examplePrompt Add all the windows with a 0.9m sill height together
994
+ *
995
+ * @performance Bulk creator — the whole batch is ONE host round-trip and ONE undo
996
+ * entry. Always prefer this over
997
+ * calling `design.create.window` in a loop: build the full `items[]` array first
998
+ * (all host walls and points up front), then make one call.
999
+ *
1000
+ * # Example
1001
+ * ```ts
1002
+ * const v = snaptrude.core.math.vec3
1003
+ * const [wall] = await snaptrude.design.query.listWalls({ isSelected: true })
1004
+ * const [casement] = await snaptrude.design.windows.listCatalog()
1005
+ * const placed = await snaptrude.design.create.windows([
1006
+ * { familyId: casement.id, hostWall: wall, position: await v.new(2, 0, 5), values: { sill: "900mm" } },
1007
+ * { familyId: casement.id, hostWall: wall, position: await v.new(5, 0, 5), values: { sill: "900mm" } },
1008
+ * ])
1009
+ * const currentWall = await snaptrude.design.query.getHost(placed[0])
1010
+ * ```
1011
+ */
1012
+ abstract windows(items: PluginCreateWindowItem[]): PluginApiReturn<ComponentHandle[]>;
1013
+ /**
1014
+ * Cut a **void** — a hole, opening or shaft — through an existing FLAT slab,
1015
+ * floor, roof or ceiling. The void is a selectable child object of its host
1016
+ * (the "Void" of the Draw Void tool). It always cuts the full host thickness.
1017
+ * It can be moved with `design.transform.move` (a move that would leave the
1018
+ * host is shortened without a report) and removed with
1019
+ * `design.delete.entities`; to resize, delete it and cut a new one
1020
+ * (`design.update.space` refuses a void).
1021
+ *
1022
+ * Give the outline **in plan** (all points at one height): its height is
1023
+ * ignored, and it is dropped straight onto the host's top face, so one outline
1024
+ * works on every storey. Keep it at least 25.4 mm (0.1 SU) inside the host
1025
+ * edge and away from other voids; merge overlapping holes into one outline.
1026
+ * Straight segments and arcs only (no splines).
1027
+ *
1028
+ * **A room has a floor finish AND a structural slab that overlap in plan; a
1029
+ * void in one does not cut the other, so a through-opening needs one void in
1030
+ * each.**
1031
+ *
1032
+ * `getEntityType` reports a void as `"void"`. Use `design.query.listVoids`
1033
+ * or `listByType("void")`; `listMasses` excludes voids. `getHost` and
1034
+ * `listChildren(host)` expose the host relationship, including after a copy.
1035
+ * Authored parametric families with a cut relationship keep their family
1036
+ * identity; discover those through family queries instead.
1037
+ *
1038
+ * Call it as `snaptrude.design.create.void(...)`; `void` is a reserved word and
1039
+ * cannot be destructured. Voids in walls, on sloped, generated or multi-plane
1040
+ * roofs, and on instanced hosts are not available yet; for a door or window
1041
+ * use `design.create.door` / `window`. To make a NEW slab that already has a
1042
+ * fixed hole, pass a contour with holes to `design.create.slab`; that hole is
1043
+ * part of the footprint, not an object. For a contour's outer loop, pass
1044
+ * `core.geom.query.contour.getOuterProfile(contour)`.
1045
+ *
1046
+ * # Example
1047
+ * ```ts
1048
+ * const m = 1000 / 254 // metres → Snaptrude units (SU)
1049
+ * const [slab] = await snaptrude.design.query.listByType("slab", { isSelected: true })
1050
+ * const center = await snaptrude.core.math.vec3.new(10 * m, 0, 5 * m) // plan point; y is ignored
1051
+ * const outline = await snaptrude.core.geom.create.profileRect(2 * m, 2 * m, center) // 2 m x 2 m
1052
+ * const hole = await snaptrude.design.create.void(slab, outline)
1053
+ * ```
1054
+ *
1055
+ * A round hole is two arcs (a circle handle is not a profile):
1056
+ * ```ts
1057
+ * const m = 1000 / 254
1058
+ * const { vec3 } = snaptrude.core.math
1059
+ * const g = snaptrude.core.geom.create
1060
+ * const r = 0.5 * m // 1 m diameter
1061
+ * const centre = await vec3.new(10 * m, 0, 5 * m)
1062
+ * const axis = await vec3.new(0, -1, 0)
1063
+ * const east = await vec3.new(10 * m + r, 0, 5 * m)
1064
+ * const west = await vec3.new(10 * m - r, 0, 5 * m)
1065
+ * const round = await g.profileFromCurves([await g.arc(east, west, centre, axis), await g.arc(west, east, centre, axis)])
1066
+ * await snaptrude.design.create.void(slab, round) // never destructure `void`
1067
+ * ```
1068
+ *
1069
+ * @param host - The slab, floor, roof or ceiling to cut through
1070
+ * @param outline - Closed, flat plan outline (world SU); its height is ignored
1071
+ * @returns the {@linkcode ComponentHandle} of the new void
1072
+ * @throws `VALIDATION` if the outline is open, crosses itself, is not flat or
1073
+ * has a spline, or the arguments are the wrong handle kinds or swapped;
1074
+ * `HANDLE_INVALID` if a handle is unknown or released or the host was
1075
+ * deleted; `HANDLE_STALE` if the host was rebuilt (re-query it);
1076
+ * `PRECONDITION_FAILED` if the
1077
+ * host is a wall or not a slab/floor/roof/ceiling, is sloped, instanced, in
1078
+ * another building, locked, outside the active proposal, a generated roof or
1079
+ * not a single plate, or there is no active structure (`engineCode`
1080
+ * `NO_ACTIVE_STRUCTURE`); `OPERATION_FAILED` with `engineCode`
1081
+ * `VOID_DOES_NOT_FIT` when the outline crosses the host edge, overlaps a void
1082
+ * or hole, is closer than 25.4 mm to either, or the fit could not be checked,
1083
+ * or another `engineCode` when the cut failed (nothing is created, except
1084
+ * `PUBLISH_FAILED` with a hint that the voids are in the scene: undo, then
1085
+ * retry); `METHOD_NOT_PERMITTED` if the plugin may not write.
1086
+ *
1087
+ * @examplePrompt Cut a hole in this slab
1088
+ * @examplePrompt Add a 1.2m by 2.4m stair opening in the first-floor slab
1089
+ * @examplePrompt Make a 600 x 600 service penetration in the floor for the riser
1090
+ * @examplePrompt Put a skylight opening through the roof
1091
+ * @examplePrompt Cut a round 1m duct hole in the slab
1092
+ * @examplePrompt Make a cut-out in the ceiling for the light well
1093
+ * @examplePrompt Add a double-height atrium void in the level 2 floor
1094
+ *
1095
+ * @performance Single-void creator. For MORE THAN ONE void, call
1096
+ * `design.create.voids(items[])`: one host round-trip, ONE undo entry, one cut
1097
+ * per host.
1098
+ */
1099
+ abstract void(host: ComponentHandle, outline: ProfileHandle): PluginApiReturn<ComponentHandle>;
1100
+ /**
1101
+ * Cut **many voids** (holes, openings, shafts) through slabs, floors, roofs
1102
+ * and ceilings in one undoable operation (bulk plural of {@linkcode void}).
1103
+ * Items may share a host or use different hosts — one shaft outline on every
1104
+ * storey's slab AND floor is one call. Validate-all-or-throw: one item whose
1105
+ * host does not contain the outline rejects the whole batch, so pass only the
1106
+ * hosts that contain it; `details.itemIndex` names the failing item (for two
1107
+ * overlapping items of the batch, the earlier one). At most 50 voids per host
1108
+ * and 200 in all per call. Same outline rules as {@linkcode void}: plan outline, 25.4 mm
1109
+ * (0.1 SU) clearance, floor AND slab are separate hosts. Call it as
1110
+ * `snaptrude.design.create.voids(...)`.
1111
+ *
1112
+ * # Example
1113
+ * ```ts
1114
+ * const m = 1000 / 254
1115
+ * // The user selects the slabs AND floors the shaft passes through; every one must contain the outline.
1116
+ * const hosts = [
1117
+ * ...(await snaptrude.design.query.listByType("slab", { isSelected: true })),
1118
+ * ...(await snaptrude.design.query.listByType("floor", { isSelected: true })),
1119
+ * ]
1120
+ * const centre = await snaptrude.core.math.vec3.new(12 * m, 0, -6 * m)
1121
+ * const shaft = await snaptrude.core.geom.create.profileRect(2 * m, 2 * m, centre)
1122
+ * const holes = await snaptrude.design.create.voids(hosts.map((host) => ({ host, outline: shaft })))
1123
+ * ```
1124
+ *
1125
+ * @param items - One {@linkcode PluginCreateVoidItem} per void (≥1, ≤200; ≤50 per host)
1126
+ * @returns the new voids as {@linkcode ComponentHandle}`[]`, in input order
1127
+ * @throws `VALIDATION` if the items fail the schema (empty array, more than
1128
+ * 1000 items, unknown fields), an outline is invalid (as for
1129
+ * {@linkcode void}), more than 50 items share one host, or there are more
1130
+ * than 200 items; plus every code {@linkcode void} throws, each with
1131
+ * `details.itemIndex`. Nothing is created on any failure, except
1132
+ * `PUBLISH_FAILED` (as for {@linkcode void}).
1133
+ *
1134
+ * @examplePrompt Cut a lift shaft through every floor slab of the core
1135
+ * @examplePrompt Cut a 2m x 2m shaft through all the slabs at this location
1136
+ * @examplePrompt Make stair openings in all the floors above the staircases
1137
+ * @examplePrompt Make holes in the roof for these three skylights
1138
+ * @examplePrompt Cut openings in each storey's slab matching this outline
1139
+ * @examplePrompt Punch the same riser penetration through every floor at once
1140
+ *
1141
+ * @performance ONE host round-trip, ONE undo entry, ONE cut per host. Never call
1142
+ * `void` in a loop. Runs synchronously on the main thread: 50 voids on one
1143
+ * host take about 1 s, and the time grows with the number of hosts (caps:
1144
+ * 50 per host, 200 per call).
1145
+ */
1146
+ abstract voids(items: PluginCreateVoidItem[]): PluginApiReturn<ComponentHandle[]>;
1147
+ /**
1148
+ * Place a parametric **door or window** into a host wall with parameter overrides.
606
1149
  *
607
1150
  * The world `position` is projected onto the host wall to locate the opening.
608
1151
  * All supplied dimensions use Snaptrude engine units. Window `sillHeight` is
609
1152
  * measured from the host wall base to the bottom of the window, not to
610
1153
  * its center. Placement is asynchronous and committed as one undoable creation.
611
1154
  *
612
- * @param options - Opening kind, catalog and host references, placement, and
613
- * optional facing, label, and dimensions
1155
+ * Wall only. For a hole in a slab, floor or roof use `design.create.void`.
1156
+ *
1157
+ * @param options - Opening kind, family and host references, placement, and
1158
+ * optional facing (swing side), hinge (hinged jamb), label, and dimensions
614
1159
  * @returns the {@linkcode ComponentHandle} of the placed door or window
615
- * @throws if the options are invalid, the catalog id is unknown, the host is
1160
+ * @throws if the options are invalid, the family id is unknown, the host is
616
1161
  * not a wall, loading fails, or the opening cannot be placed on the host
617
1162
  *
618
1163
  * @examplePrompt Add a 1m wide door to this wall here
619
1164
  * @examplePrompt Place a window with a 0.9m sill height on the selected wall
620
1165
  *
621
- * @performance Single-opening creator — use it for one hosted opening. A plural
622
- * API is intentionally unavailable until host placement can be atomic.
1166
+ * @performance Single-opening creator — use it for one hosted opening. For MORE
1167
+ * THAN ONE, call `design.create.doors(items[])` / `design.create.windows(items[])`:
1168
+ * the same per-item fields, one host round-trip, ONE undo entry.
623
1169
  *
624
1170
  * # Example
625
1171
  * ```ts
626
1172
  * const opening = await snaptrude.design.create.opening({
627
1173
  * kind: "window",
628
- * catalogId: windowType.id,
1174
+ * familyId: windowType.id,
629
1175
  * hostWall: wall,
630
1176
  * position: await snaptrude.core.math.vec3.new(3, 0, 5),
631
1177
  * width: 1.2,
@@ -801,6 +1347,32 @@ export declare abstract class PluginDesignCreateApi {
801
1347
  * ```
802
1348
  */
803
1349
  abstract buildableEnvelope(sitePolygon: PluginBuildableEnvelopePolygonVertex[], lengthUnit: "ft" | "m", setbacks: PluginBuildableEnvelopeSetbackTier[], verticalCap: PluginBuildableEnvelopeVerticalCap, floorToFloor: number, farRatio?: number, lotCoverageMaxPct?: number): PluginApiReturn<PluginBuildableEnvelopeCreateResult>;
1350
+ /**
1351
+ * Create a default buildable envelope for an existing site — the same as the
1352
+ * right panel's "Create Buildable Envelope" button. Front, side and rear
1353
+ * distances are seeded from Site Analysis or the Program sheet, with a 10 ft
1354
+ * fallback, and the envelope is linked to the site. Call it only after the
1355
+ * user agrees (for example when `design.update.siteEdge` throws
1356
+ * `NO_BUILDABLE_ENVELOPE`).
1357
+ *
1358
+ * @param siteId - Site component id, from `program.site.listEdges()`.
1359
+ * @returns A {@linkcode PluginDesignCreateBuildableEnvelopeFromSiteResult}
1360
+ * with the `buildableEnvelopeId` of the created envelope.
1361
+ * @throws `HANDLE_INVALID` for an unknown `siteId`. `PRECONDITION_FAILED`
1362
+ * (`details.reason: "SITE_HAS_ENVELOPE"`) when the site already has an
1363
+ * envelope.
1364
+ *
1365
+ * @examplePrompt Create a buildable envelope for this site with default setbacks
1366
+ * @examplePrompt Add the zoning envelope to my site
1367
+ *
1368
+ * # Example
1369
+ * ```ts
1370
+ * const [{ siteId }] = (await snaptrude.program.site.listEdges()).sites
1371
+ * const { buildableEnvelopeId } =
1372
+ * await snaptrude.design.create.buildableEnvelopeFromSite(siteId)
1373
+ * ```
1374
+ */
1375
+ abstract buildableEnvelopeFromSite(siteId: string): PluginApiReturn<PluginDesignCreateBuildableEnvelopeFromSiteResult>;
804
1376
  }
805
1377
  /**
806
1378
  * Line style of a reference line (mirrors the engine `ReferenceLineMode` verbatim).
@@ -903,11 +1475,11 @@ export declare const PluginDesignCreateSpaceArgs: z.ZodObject<{
903
1475
  Parking: "Parking";
904
1476
  }>>;
905
1477
  massType: z.ZodOptional<z.ZodEnum<{
1478
+ Furniture: "Furniture";
906
1479
  Room: "Room";
907
1480
  Plinth: "Plinth";
908
1481
  Void: "Void";
909
1482
  Pergola: "Pergola";
910
- Furniture: "Furniture";
911
1483
  "Facade element": "Facade element";
912
1484
  "Generic mass": "Generic mass";
913
1485
  Department: "Department";
@@ -942,11 +1514,11 @@ export declare const PluginDesignCreateMassArgs: z.ZodObject<{
942
1514
  label: z.ZodOptional<z.ZodString>;
943
1515
  position: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>>;
944
1516
  massType: z.ZodOptional<z.ZodEnum<{
1517
+ Furniture: "Furniture";
945
1518
  Room: "Room";
946
1519
  Plinth: "Plinth";
947
1520
  Void: "Void";
948
1521
  Pergola: "Pergola";
949
- Furniture: "Furniture";
950
1522
  "Facade element": "Facade element";
951
1523
  "Generic mass": "Generic mass";
952
1524
  Department: "Department";
@@ -1078,15 +1650,24 @@ export type PluginDesignCreateBeamArgs = z.infer<typeof PluginDesignCreateBeamAr
1078
1650
  * | `profile` | {@linkcode ProfileHandle} | Ordered curve chain (wall centerlines) |
1079
1651
  * | `height` | `number`? | Wall height (default engine default) |
1080
1652
  * | `thickness` | `number`? | Wall thickness (default: `wallType`'s total layer thickness when given, else engine default) |
1081
- * | `wallType` | `string`? | Wall type name from `design.types.list("wall")` — layers/material/thickness defaults (default generic) |
1653
+ * | `wallType` | {@linkcode PluginWallType}? | Legacy name/id or exact native `{ id, version }` pin from `design.types.list("wall")` (default generic) |
1082
1654
  * | `storey` | `number`? | Target storey (integer, must exist) — walls assigned + lifted to its base in the same undo entry (default: geometry-derived) |
1655
+ * | `topProfiles` | ({@linkcode PluginWallTopProfile} \| `null`)[]? | Top edge per curve (same order); `null`/missing = flat at `height`. Straight curves only |
1083
1656
  */
1084
1657
  export declare const PluginDesignCreateWallsArgs: z.ZodObject<{
1085
1658
  profile: z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"profile">, string>>;
1086
1659
  height: z.ZodOptional<z.ZodNumber>;
1087
1660
  thickness: z.ZodOptional<z.ZodNumber>;
1088
- wallType: z.ZodOptional<z.ZodString>;
1661
+ wallType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodObject<{
1662
+ id: z.ZodString;
1663
+ version: z.ZodNumber;
1664
+ }, z.core.$strip>]>>;
1089
1665
  storey: z.ZodOptional<z.ZodNumber>;
1666
+ topProfiles: z.ZodOptional<z.ZodArray<z.ZodNullable<z.ZodArray<z.ZodObject<{
1667
+ along: z.ZodNumber;
1668
+ height: z.ZodNumber;
1669
+ }, z.core.$strip>>>>>;
1670
+ values: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString, z.ZodBoolean]>>>;
1090
1671
  }, z.core.$strip>;
1091
1672
  export type PluginDesignCreateWallsArgs = z.infer<typeof PluginDesignCreateWallsArgs>;
1092
1673
  /**
@@ -1141,7 +1722,7 @@ export type PluginDesignCreateStaircaseArgs = z.infer<typeof PluginDesignCreateS
1141
1722
  * | `catalogId` | `string` | Library id: team `_id` or general `fullName` |
1142
1723
  * | `position` | {@linkcode Vec3Handle} | Absolute world placement point |
1143
1724
  * | `label` | `string`? | Instance name (default auto `${name}Ins${n}`) |
1144
- * | `createNewSourceMesh` | `boolean`? | Emit a source-mesh creation command (default `true`) |
1725
+ * | `createNewSourceMesh` | `boolean`? | Legacy, kept for compatibility; the host records a catalog source exactly once and this flag cannot skip it |
1145
1726
  * | `angleInDegrees` | `number`? | Rotation about the vertical axis, in degrees (default unrotated) |
1146
1727
  */
1147
1728
  export declare const PluginDesignCreateFurnitureArgs: z.ZodObject<{
@@ -1157,18 +1738,26 @@ export type PluginDesignCreateFurnitureArgs = z.infer<typeof PluginDesignCreateF
1157
1738
  *
1158
1739
  * | Property | Type | Description |
1159
1740
  * |---|---|---|
1160
- * | `catalogId` | `string` | Library id: team `_id` or general `fullName` |
1741
+ * | `familyId` | `string` | Hosted door family definition ID |
1742
+ * | `version` | `number`? | Exact version; newest known by default |
1743
+ * | `values` | `Record<string, number \| string>`? | Parameters; numeric lengths use SU |
1161
1744
  * | `hostWall` | {@linkcode ComponentHandle} | The wall to host the door |
1162
1745
  * | `position` | {@linkcode Vec3Handle} | World point projected onto the wall |
1163
1746
  * | `label` | `string`? | Instance name (optional) |
1164
- * | `facing` | {@linkcode Vec3Handle}? | World point on the side of the wall the door faces (default engine-chosen) |
1747
+ * | `facing` | {@linkcode Vec3Handle}? | World point on the side of the wall the door swings open to (default engine-chosen) |
1748
+ * | `hinge` | {@linkcode Vec3Handle}? | World point near the hinged jamb; requires hand control |
1165
1749
  */
1166
1750
  export declare const PluginDesignCreateDoorArgs: z.ZodObject<{
1167
- catalogId: z.ZodString;
1751
+ familyId: z.ZodString;
1752
+ version: z.ZodOptional<z.ZodNumber>;
1753
+ values: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>;
1168
1754
  hostWall: z.ZodPipe<z.ZodString, z.ZodTransform<ComponentHandle, string>>;
1169
1755
  position: z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>;
1170
- label: z.ZodOptional<z.ZodString>;
1171
1756
  facing: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>>;
1757
+ hinge: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>>;
1758
+ label: z.ZodOptional<z.ZodString>;
1759
+ width: z.ZodOptional<z.ZodNumber>;
1760
+ height: z.ZodOptional<z.ZodNumber>;
1172
1761
  }, z.core.$strip>;
1173
1762
  export type PluginDesignCreateDoorArgs = z.infer<typeof PluginDesignCreateDoorArgs>;
1174
1763
  /**
@@ -1176,18 +1765,26 @@ export type PluginDesignCreateDoorArgs = z.infer<typeof PluginDesignCreateDoorAr
1176
1765
  *
1177
1766
  * | Property | Type | Description |
1178
1767
  * |---|---|---|
1179
- * | `catalogId` | `string` | Library id: team `_id` or general `fullName` |
1768
+ * | `familyId` | `string` | Hosted window family definition ID |
1769
+ * | `version` | `number`? | Exact version; newest known by default |
1770
+ * | `values` | `Record<string, number \| string>`? | Parameters; numeric lengths use SU |
1180
1771
  * | `hostWall` | {@linkcode ComponentHandle} | The wall to host the window |
1181
1772
  * | `position` | {@linkcode Vec3Handle} | World point projected onto the wall |
1182
1773
  * | `label` | `string`? | Instance name (optional) |
1183
- * | `facing` | {@linkcode Vec3Handle}? | World point on the side of the wall the window faces (default engine-chosen) |
1774
+ * | `facing` | {@linkcode Vec3Handle}? | World point on the side of the wall the window opens to (default engine-chosen) |
1775
+ * | `hinge` | {@linkcode Vec3Handle}? | World point near the hinged jamb; requires hand control |
1184
1776
  */
1185
1777
  export declare const PluginDesignCreateWindowArgs: z.ZodObject<{
1186
- catalogId: z.ZodString;
1778
+ familyId: z.ZodString;
1779
+ version: z.ZodOptional<z.ZodNumber>;
1780
+ values: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>;
1187
1781
  hostWall: z.ZodPipe<z.ZodString, z.ZodTransform<ComponentHandle, string>>;
1188
1782
  position: z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>;
1189
- label: z.ZodOptional<z.ZodString>;
1190
1783
  facing: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>>;
1784
+ hinge: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>>;
1785
+ label: z.ZodOptional<z.ZodString>;
1786
+ width: z.ZodOptional<z.ZodNumber>;
1787
+ height: z.ZodOptional<z.ZodNumber>;
1191
1788
  }, z.core.$strip>;
1192
1789
  export type PluginDesignCreateWindowArgs = z.infer<typeof PluginDesignCreateWindowArgs>;
1193
1790
  /**
@@ -1197,20 +1794,26 @@ export type PluginDesignCreateWindowArgs = z.infer<typeof PluginDesignCreateWind
1197
1794
  * the distance from the host wall base to the bottom of the window.
1198
1795
  */
1199
1796
  export declare const PluginDesignCreateOpeningOptions: z.ZodDiscriminatedUnion<[z.ZodObject<{
1200
- catalogId: z.ZodString;
1797
+ familyId: z.ZodString;
1798
+ version: z.ZodOptional<z.ZodNumber>;
1799
+ values: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>;
1201
1800
  hostWall: z.ZodPipe<z.ZodString, z.ZodTransform<ComponentHandle, string>>;
1202
1801
  position: z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>;
1203
1802
  facing: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>>;
1803
+ hinge: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>>;
1204
1804
  label: z.ZodOptional<z.ZodString>;
1205
1805
  width: z.ZodOptional<z.ZodNumber>;
1206
1806
  height: z.ZodOptional<z.ZodNumber>;
1207
1807
  kind: z.ZodLiteral<"door">;
1208
1808
  }, z.core.$strict>, z.ZodObject<{
1209
1809
  sillHeight: z.ZodOptional<z.ZodNumber>;
1210
- catalogId: z.ZodString;
1810
+ familyId: z.ZodString;
1811
+ version: z.ZodOptional<z.ZodNumber>;
1812
+ values: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodUnion<readonly [z.ZodNumber, z.ZodString]>>>;
1211
1813
  hostWall: z.ZodPipe<z.ZodString, z.ZodTransform<ComponentHandle, string>>;
1212
1814
  position: z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>;
1213
1815
  facing: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>>;
1816
+ hinge: z.ZodOptional<z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"vec3">, string>>>;
1214
1817
  label: z.ZodOptional<z.ZodString>;
1215
1818
  width: z.ZodOptional<z.ZodNumber>;
1216
1819
  height: z.ZodOptional<z.ZodNumber>;
@@ -1271,8 +1874,53 @@ export type PluginSmartLayoutResult = z.infer<typeof PluginSmartLayoutResult>;
1271
1874
  * | `style` | {@linkcode PluginReferenceLineStyle}? | Line style (default `SOLID`) |
1272
1875
  * | `gridTag` | `string`? | Grid tag label (default `"A"`) |
1273
1876
  */
1877
+ /**
1878
+ * Reference-line creation options. styleId selects a project pen/pattern; its
1879
+ * native legacy mirror is saved too. Omitted options preserve tool defaults.
1880
+ */
1881
+ export declare const PluginReferenceLineOptions: z.ZodObject<{
1882
+ styleId: z.ZodOptional<z.ZodEnum<{
1883
+ hidden: "hidden";
1884
+ thin: "thin";
1885
+ medium: "medium";
1886
+ wide: "wide";
1887
+ overhead: "overhead";
1888
+ demolished: "demolished";
1889
+ centerline: "centerline";
1890
+ }>>;
1891
+ color: z.ZodOptional<z.ZodString>;
1892
+ thickness: z.ZodOptional<z.ZodNumber>;
1893
+ style: z.ZodOptional<z.ZodEnum<{
1894
+ SOLID: "SOLID";
1895
+ DASHED: "DASHED";
1896
+ DOT_DASH: "DOT_DASH";
1897
+ }>>;
1898
+ }, z.core.$strict>;
1899
+ export type PluginReferenceLineOptions = z.infer<typeof PluginReferenceLineOptions>;
1900
+ /**
1901
+ * Normalized arguments. The host maps the second positional argument to either
1902
+ * the legacy color field or options; mixing those forms is rejected atomically.
1903
+ */
1274
1904
  export declare const PluginDesignCreateReferenceLinesArgs: z.ZodObject<{
1275
1905
  profile: z.ZodPipe<z.ZodPipe<z.ZodTransform<unknown, unknown>, z.ZodString>, z.ZodTransform<import("../../..").Handle<"profile">, string>>;
1906
+ options: z.ZodOptional<z.ZodObject<{
1907
+ styleId: z.ZodOptional<z.ZodEnum<{
1908
+ hidden: "hidden";
1909
+ thin: "thin";
1910
+ medium: "medium";
1911
+ wide: "wide";
1912
+ overhead: "overhead";
1913
+ demolished: "demolished";
1914
+ centerline: "centerline";
1915
+ }>>;
1916
+ color: z.ZodOptional<z.ZodString>;
1917
+ thickness: z.ZodOptional<z.ZodNumber>;
1918
+ style: z.ZodOptional<z.ZodEnum<{
1919
+ SOLID: "SOLID";
1920
+ DASHED: "DASHED";
1921
+ DOT_DASH: "DOT_DASH";
1922
+ }>>;
1923
+ }, z.core.$strict>>;
1276
1924
  color: z.ZodOptional<z.ZodString>;
1277
1925
  thickness: z.ZodOptional<z.ZodNumber>;
1278
1926
  style: z.ZodOptional<z.ZodEnum<{
@@ -1281,7 +1929,7 @@ export declare const PluginDesignCreateReferenceLinesArgs: z.ZodObject<{
1281
1929
  DOT_DASH: "DOT_DASH";
1282
1930
  }>>;
1283
1931
  gridTag: z.ZodOptional<z.ZodString>;
1284
- }, z.core.$strip>;
1932
+ }, z.core.$strict>;
1285
1933
  export type PluginDesignCreateReferenceLinesArgs = z.infer<typeof PluginDesignCreateReferenceLinesArgs>;
1286
1934
  /**
1287
1935
  * Copy mode for {@linkcode PluginDesignCreateApi.copy}.
@@ -1349,11 +1997,11 @@ export declare const PluginCreateSpaceItem: z.ZodObject<{
1349
1997
  Parking: "Parking";
1350
1998
  }>>;
1351
1999
  massType: z.ZodOptional<z.ZodEnum<{
2000
+ Furniture: "Furniture";
1352
2001
  Room: "Room";
1353
2002
  Plinth: "Plinth";
1354
2003
  Void: "Void";
1355
2004
  Pergola: "Pergola";
1356
- Furniture: "Furniture";
1357
2005
  "Facade element": "Facade element";
1358
2006
  "Generic mass": "Generic mass";
1359
2007
  Department: "Department";
@@ -1371,4 +2019,7 @@ export declare const PluginCreateSpaceItem: z.ZodObject<{
1371
2019
  storey: z.ZodOptional<z.ZodNumber>;
1372
2020
  }, z.core.$strip>;
1373
2021
  export type PluginCreateSpaceItem = z.infer<typeof PluginCreateSpaceItem>;
2022
+ export * from "./opening-fields";
2023
+ export * from "./bulk-items";
2024
+ export * from "./grids";
1374
2025
  //# sourceMappingURL=index.d.ts.map