@snaptrude/plugin-core 0.0.0-dev-20260708130115 → 0.0.0-dev-20260827194031

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 (261) hide show
  1. package/CHANGELOG.md +152 -1
  2. package/api-manifest.json +3643 -276
  3. package/dist/api/analysis/daylight.d.ts +603 -0
  4. package/dist/api/analysis/daylight.d.ts.map +1 -0
  5. package/dist/api/analysis/heatmaps.d.ts +658 -0
  6. package/dist/api/analysis/heatmaps.d.ts.map +1 -0
  7. package/dist/api/analysis/illuminance.d.ts +145 -0
  8. package/dist/api/analysis/illuminance.d.ts.map +1 -0
  9. package/dist/api/analysis/index.d.ts +59 -0
  10. package/dist/api/analysis/index.d.ts.map +1 -0
  11. package/dist/api/analysis/shadows.d.ts +165 -0
  12. package/dist/api/analysis/shadows.d.ts.map +1 -0
  13. package/dist/api/analysis/solar.d.ts +249 -0
  14. package/dist/api/analysis/solar.d.ts.map +1 -0
  15. package/dist/api/analysis/sunlightHours.d.ts +208 -0
  16. package/dist/api/analysis/sunlightHours.d.ts.map +1 -0
  17. package/dist/api/analysis/sunpath.d.ts +80 -0
  18. package/dist/api/analysis/sunpath.d.ts.map +1 -0
  19. package/dist/api/analysis/weather.d.ts +193 -0
  20. package/dist/api/analysis/weather.d.ts.map +1 -0
  21. package/dist/api/core/camera/index.d.ts +261 -0
  22. package/dist/api/core/camera/index.d.ts.map +1 -0
  23. package/dist/api/core/comment/index.d.ts +105 -2
  24. package/dist/api/core/comment/index.d.ts.map +1 -1
  25. package/dist/api/core/geom/create/index.d.ts +840 -14
  26. package/dist/api/core/geom/create/index.d.ts.map +1 -1
  27. package/dist/api/core/geom/delete/index.d.ts +8 -2
  28. package/dist/api/core/geom/delete/index.d.ts.map +1 -1
  29. package/dist/api/core/geom/query/arc.d.ts +5 -5
  30. package/dist/api/core/geom/query/brep.d.ts +130 -18
  31. package/dist/api/core/geom/query/brep.d.ts.map +1 -1
  32. package/dist/api/core/geom/query/circle.d.ts +18 -18
  33. package/dist/api/core/geom/query/contour.d.ts +20 -20
  34. package/dist/api/core/geom/query/curve.d.ts +49 -49
  35. package/dist/api/core/geom/query/edge.d.ts +5 -5
  36. package/dist/api/core/geom/query/face.d.ts +16 -16
  37. package/dist/api/core/geom/query/halfedge.d.ts +8 -8
  38. package/dist/api/core/geom/query/profile.d.ts +19 -19
  39. package/dist/api/core/geom/query/vertex.d.ts +8 -8
  40. package/dist/api/core/geom/update/contour.d.ts +14 -14
  41. package/dist/api/core/geom/update/curve.d.ts +7 -7
  42. package/dist/api/core/geom/update/profile.d.ts +16 -16
  43. package/dist/api/core/handles/index.d.ts +210 -0
  44. package/dist/api/core/handles/index.d.ts.map +1 -0
  45. package/dist/api/core/index.d.ts +34 -0
  46. package/dist/api/core/index.d.ts.map +1 -1
  47. package/dist/api/core/io/export/index.d.ts +134 -0
  48. package/dist/api/core/io/export/index.d.ts.map +1 -0
  49. package/dist/api/core/io/import/index.d.ts +453 -0
  50. package/dist/api/core/io/import/index.d.ts.map +1 -0
  51. package/dist/api/core/io/index.d.ts +40 -0
  52. package/dist/api/core/io/index.d.ts.map +1 -0
  53. package/dist/api/core/io/job/index.d.ts +139 -0
  54. package/dist/api/core/io/job/index.d.ts.map +1 -0
  55. package/dist/api/core/io/query/index.d.ts +74 -0
  56. package/dist/api/core/io/query/index.d.ts.map +1 -0
  57. package/dist/api/core/io/terrain/index.d.ts +341 -0
  58. package/dist/api/core/io/terrain/index.d.ts.map +1 -0
  59. package/dist/api/core/io/underlay/index.d.ts +805 -0
  60. package/dist/api/core/io/underlay/index.d.ts.map +1 -0
  61. package/dist/api/core/layers.d.ts +7 -7
  62. package/dist/api/core/mode/index.d.ts +99 -0
  63. package/dist/api/core/mode/index.d.ts.map +1 -0
  64. package/dist/api/core/project/index.d.ts +68 -1
  65. package/dist/api/core/project/index.d.ts.map +1 -1
  66. package/dist/api/core/proposals/index.d.ts +531 -0
  67. package/dist/api/core/proposals/index.d.ts.map +1 -0
  68. package/dist/api/core/storeys/index.d.ts +265 -0
  69. package/dist/api/core/storeys/index.d.ts.map +1 -0
  70. package/dist/api/core/tags.d.ts +24 -0
  71. package/dist/api/core/tags.d.ts.map +1 -1
  72. package/dist/api/core/user.d.ts +44 -0
  73. package/dist/api/core/user.d.ts.map +1 -0
  74. package/dist/api/core/zoom/index.d.ts +4 -0
  75. package/dist/api/core/zoom/index.d.ts.map +1 -1
  76. package/dist/api/design/boolean/index.d.ts +4 -4
  77. package/dist/api/design/create/index.d.ts +568 -45
  78. package/dist/api/design/create/index.d.ts.map +1 -1
  79. package/dist/api/design/delete/index.d.ts +3 -0
  80. package/dist/api/design/delete/index.d.ts.map +1 -1
  81. package/dist/api/design/doors/index.d.ts +195 -0
  82. package/dist/api/design/doors/index.d.ts.map +1 -1
  83. package/dist/api/design/edit/index.d.ts +1 -1
  84. package/dist/api/design/erase/index.d.ts +2 -2
  85. package/dist/api/design/family.d.ts +493 -0
  86. package/dist/api/design/family.d.ts.map +1 -0
  87. package/dist/api/design/furniture/index.d.ts +181 -8
  88. package/dist/api/design/furniture/index.d.ts.map +1 -1
  89. package/dist/api/design/index.d.ts +98 -0
  90. package/dist/api/design/index.d.ts.map +1 -1
  91. package/dist/api/design/lock.d.ts +26 -0
  92. package/dist/api/design/lock.d.ts.map +1 -1
  93. package/dist/api/design/materials/index.d.ts +270 -16
  94. package/dist/api/design/materials/index.d.ts.map +1 -1
  95. package/dist/api/design/query/geometry/index.d.ts +112 -0
  96. package/dist/api/design/query/geometry/index.d.ts.map +1 -1
  97. package/dist/api/design/query/index.d.ts +289 -11
  98. package/dist/api/design/query/index.d.ts.map +1 -1
  99. package/dist/api/design/query/referenceLines.d.ts +45 -0
  100. package/dist/api/design/query/referenceLines.d.ts.map +1 -0
  101. package/dist/api/design/query/spaces.d.ts +181 -8
  102. package/dist/api/design/query/spaces.d.ts.map +1 -1
  103. package/dist/api/design/selection/index.d.ts +144 -0
  104. package/dist/api/design/selection/index.d.ts.map +1 -1
  105. package/dist/api/design/transform/index.d.ts +172 -10
  106. package/dist/api/design/transform/index.d.ts.map +1 -1
  107. package/dist/api/design/types/index.d.ts +181 -0
  108. package/dist/api/design/types/index.d.ts.map +1 -0
  109. package/dist/api/design/update/index.d.ts +553 -2
  110. package/dist/api/design/update/index.d.ts.map +1 -1
  111. package/dist/api/design/visibility.d.ts +126 -0
  112. package/dist/api/design/visibility.d.ts.map +1 -0
  113. package/dist/api/design/windows/index.d.ts +113 -2
  114. package/dist/api/design/windows/index.d.ts.map +1 -1
  115. package/dist/api/entity/buildableEnvelope.d.ts +4 -0
  116. package/dist/api/entity/buildableEnvelope.d.ts.map +1 -1
  117. package/dist/api/entity/referenceLine.d.ts +10 -2
  118. package/dist/api/entity/referenceLine.d.ts.map +1 -1
  119. package/dist/api/entity/space.d.ts +21 -21
  120. package/dist/api/entity/story.d.ts +242 -15
  121. package/dist/api/entity/story.d.ts.map +1 -1
  122. package/dist/api/index.d.ts +10 -0
  123. package/dist/api/index.d.ts.map +1 -1
  124. package/dist/api/presentation/aiInspiration.d.ts +25 -25
  125. package/dist/api/presentation/annotate.d.ts +467 -0
  126. package/dist/api/presentation/annotate.d.ts.map +1 -0
  127. package/dist/api/presentation/diagrams.d.ts +111 -8
  128. package/dist/api/presentation/diagrams.d.ts.map +1 -1
  129. package/dist/api/presentation/export.d.ts +108 -0
  130. package/dist/api/presentation/export.d.ts.map +1 -0
  131. package/dist/api/presentation/import.d.ts +55 -4
  132. package/dist/api/presentation/import.d.ts.map +1 -1
  133. package/dist/api/presentation/index.d.ts +58 -1
  134. package/dist/api/presentation/index.d.ts.map +1 -1
  135. package/dist/api/presentation/placedViews.d.ts +1139 -0
  136. package/dist/api/presentation/placedViews.d.ts.map +1 -0
  137. package/dist/api/presentation/shapes.d.ts +481 -0
  138. package/dist/api/presentation/shapes.d.ts.map +1 -0
  139. package/dist/api/presentation/sheets.d.ts +452 -13
  140. package/dist/api/presentation/sheets.d.ts.map +1 -1
  141. package/dist/api/presentation/slideshow.d.ts +125 -0
  142. package/dist/api/presentation/slideshow.d.ts.map +1 -0
  143. package/dist/api/presentation/tables.d.ts +81 -0
  144. package/dist/api/presentation/tables.d.ts.map +1 -0
  145. package/dist/api/presentation/views.d.ts +367 -7
  146. package/dist/api/presentation/views.d.ts.map +1 -1
  147. package/dist/api/program/areas.d.ts +102 -12
  148. package/dist/api/program/areas.d.ts.map +1 -1
  149. package/dist/api/program/cores.d.ts +3 -99
  150. package/dist/api/program/cores.d.ts.map +1 -1
  151. package/dist/api/program/index.d.ts +7 -15
  152. package/dist/api/program/index.d.ts.map +1 -1
  153. package/dist/api/program/layout.d.ts +346 -11
  154. package/dist/api/program/layout.d.ts.map +1 -1
  155. package/dist/api/program/site.d.ts +469 -13
  156. package/dist/api/program/site.d.ts.map +1 -1
  157. package/dist/api/program/spreadsheet.d.ts +365 -41
  158. package/dist/api/program/spreadsheet.d.ts.map +1 -1
  159. package/dist/api/workspace/index.d.ts +505 -0
  160. package/dist/api/workspace/index.d.ts.map +1 -0
  161. package/dist/errors/codes.d.ts +34 -0
  162. package/dist/errors/codes.d.ts.map +1 -0
  163. package/dist/errors/envelope.d.ts +56 -0
  164. package/dist/errors/envelope.d.ts.map +1 -0
  165. package/dist/errors/index.d.ts +6 -0
  166. package/dist/errors/index.d.ts.map +1 -0
  167. package/dist/errors/plugin-error.d.ts +69 -0
  168. package/dist/errors/plugin-error.d.ts.map +1 -0
  169. package/dist/handles.d.ts +97 -25
  170. package/dist/handles.d.ts.map +1 -1
  171. package/dist/host-utils.d.ts +4 -0
  172. package/dist/host-utils.d.ts.map +1 -1
  173. package/dist/index.cjs +4605 -1423
  174. package/dist/index.cjs.map +1 -1
  175. package/dist/index.d.ts +1 -0
  176. package/dist/index.d.ts.map +1 -1
  177. package/dist/index.js +4191 -1412
  178. package/dist/index.js.map +1 -1
  179. package/package.json +4 -2
  180. package/scripts/generate-manifest.mjs +45 -0
  181. package/scripts/generate-manifest.test.mjs +103 -4
  182. package/src/api/analysis/daylight.ts +470 -0
  183. package/src/api/analysis/heatmaps.ts +683 -0
  184. package/src/api/analysis/illuminance.ts +155 -0
  185. package/src/api/analysis/index.ts +61 -0
  186. package/src/api/analysis/shadows.ts +183 -0
  187. package/src/api/analysis/solar.ts +237 -0
  188. package/src/api/analysis/sunlightHours.ts +211 -0
  189. package/src/api/analysis/sunpath.ts +83 -0
  190. package/src/api/analysis/weather.ts +179 -0
  191. package/src/api/core/camera/index.ts +268 -0
  192. package/src/api/core/comment/index.ts +120 -2
  193. package/src/api/core/geom/create/index.ts +912 -1
  194. package/src/api/core/geom/delete/index.ts +6 -0
  195. package/src/api/core/geom/query/brep.ts +119 -0
  196. package/src/api/core/handles/index.ts +233 -0
  197. package/src/api/core/index.ts +34 -0
  198. package/src/api/core/io/export/index.ts +126 -0
  199. package/src/api/core/io/import/index.ts +496 -0
  200. package/src/api/core/io/index.ts +42 -0
  201. package/src/api/core/io/job/index.ts +140 -0
  202. package/src/api/core/io/query/index.ts +71 -0
  203. package/src/api/core/io/terrain/index.ts +360 -0
  204. package/src/api/core/io/underlay/index.ts +705 -0
  205. package/src/api/core/mode/index.ts +96 -0
  206. package/src/api/core/project/index.ts +62 -1
  207. package/src/api/core/proposals/index.ts +569 -0
  208. package/src/api/core/storeys/index.ts +294 -0
  209. package/src/api/core/tags.ts +27 -0
  210. package/src/api/core/user.ts +46 -0
  211. package/src/api/core/zoom/index.ts +4 -0
  212. package/src/api/design/create/index.ts +670 -30
  213. package/src/api/design/delete/index.ts +3 -0
  214. package/src/api/design/doors/index.ts +208 -0
  215. package/src/api/design/erase/index.ts +1 -1
  216. package/src/api/design/family.ts +544 -0
  217. package/src/api/design/furniture/index.ts +197 -8
  218. package/src/api/design/index.ts +102 -0
  219. package/src/api/design/lock.ts +27 -0
  220. package/src/api/design/materials/index.ts +334 -27
  221. package/src/api/design/query/geometry/index.ts +125 -3
  222. package/src/api/design/query/index.ts +219 -7
  223. package/src/api/design/query/referenceLines.ts +52 -0
  224. package/src/api/design/query/spaces.ts +143 -0
  225. package/src/api/design/selection/index.ts +129 -0
  226. package/src/api/design/transform/index.ts +170 -9
  227. package/src/api/design/types/index.ts +156 -0
  228. package/src/api/design/update/index.ts +631 -3
  229. package/src/api/design/visibility.ts +143 -0
  230. package/src/api/design/windows/index.ts +128 -2
  231. package/src/api/entity/buildableEnvelope.ts +4 -0
  232. package/src/api/entity/referenceLine.ts +8 -0
  233. package/src/api/entity/story.ts +259 -15
  234. package/src/api/index.ts +10 -0
  235. package/src/api/presentation/annotate.ts +385 -0
  236. package/src/api/presentation/diagrams.ts +118 -8
  237. package/src/api/presentation/export.ts +108 -0
  238. package/src/api/presentation/import.ts +51 -4
  239. package/src/api/presentation/index.ts +66 -1
  240. package/src/api/presentation/placedViews.ts +1120 -0
  241. package/src/api/presentation/shapes.ts +274 -0
  242. package/src/api/presentation/sheets.ts +400 -13
  243. package/src/api/presentation/slideshow.ts +134 -0
  244. package/src/api/presentation/tables.ts +84 -0
  245. package/src/api/presentation/views.ts +376 -8
  246. package/src/api/program/areas.ts +88 -15
  247. package/src/api/program/cores.ts +3 -91
  248. package/src/api/program/index.ts +7 -15
  249. package/src/api/program/layout.ts +365 -11
  250. package/src/api/program/site.ts +435 -13
  251. package/src/api/program/spreadsheet.ts +376 -35
  252. package/src/api/workspace/index.ts +563 -0
  253. package/src/errors/codes.ts +136 -0
  254. package/src/errors/envelope.ts +75 -0
  255. package/src/errors/index.ts +21 -0
  256. package/src/errors/plugin-error.ts +134 -0
  257. package/src/handles.ts +123 -13
  258. package/src/host-utils.ts +4 -0
  259. package/src/index.ts +1 -0
  260. package/test/errors.test.mjs +184 -0
  261. package/tsconfig.json +7 -2
@@ -0,0 +1,544 @@
1
+ import * as z from "zod"
2
+ import { PluginApiReturn } from "../../types"
3
+ import { ComponentHandle, Vec3Components } from "../../handles"
4
+
5
+ /**
6
+ * `snaptrude.design.family.*` — author NATIVE parametric families from a JSON spec.
7
+ *
8
+ * A parametric family is a reusable, parameter-driven building component: a
9
+ * curtain-wall panel, a louvre screen, a balustrade, a shading fin. Unlike the
10
+ * rest of `design.*`, you do not build one out of geometry calls — you write a
11
+ * JSON **spec** describing its parameters and its geometry rules, and the host
12
+ * compiles that into a live parametric definition the user can place, flex and
13
+ * save to their library.
14
+ *
15
+ * ## Workflow
16
+ *
17
+ * ```
18
+ * getReference() read the spec DSL once — grammar, ops, expressions, example
19
+ * prepare({ bundle }) validate + compile + show a live ghost; nothing committed
20
+ * flex({ values }) re-run at new values; returns the geometry delta
21
+ * place() arm placement — the USER clicks to drop it
22
+ * create({ name }) commit it to the project's family library
23
+ * ```
24
+ *
25
+ * ## Read getReference() first
26
+ *
27
+ * The spec DSL is a closed expression language with its own op set, coordinate
28
+ * convention (**+Y up, integer millimetres** — not Snaptrude's babylon units)
29
+ * and part-naming law. It is deliberately NOT duplicated in these types:
30
+ * {@linkcode PluginDesignFamilyApi.getReference} returns the whole reference,
31
+ * generated from a family that is actually registered in the host, so the
32
+ * documentation cannot drift from what the compiler accepts.
33
+ *
34
+ * ## The repair contract
35
+ *
36
+ * {@linkcode PluginDesignFamilyApi.prepare} does **not** throw on an invalid
37
+ * spec — it returns `{ ok: false, errors }` where each error carries a JSON
38
+ * pointer into the bundle you sent (e.g. `"/root/geometry/2/body/0/w"`). Read
39
+ * `errors[0].path`, fix that node, and call `prepare` again. A failed `prepare`
40
+ * leaves the previous good draft standing, so it costs nothing but the node you
41
+ * broke. Re-authoring from scratch throws away everything already correct.
42
+ *
43
+ * Accessed via `snaptrude.design.family`.
44
+ */
45
+ export abstract class PluginDesignFamilyApi {
46
+ constructor() {}
47
+
48
+ /**
49
+ * Read the family-spec DSL reference: grammar, the op table, the expression
50
+ * whitelist, the coordinate convention, the repair contract, and a worked
51
+ * example taken from a registered family.
52
+ *
53
+ * Read this before authoring a family for the first time in a session. The
54
+ * DSL is a closed language — a guessed op or function is a rejected spec.
55
+ *
56
+ * @returns The reference text
57
+ *
58
+ * @examplePrompt How do I write a parametric family spec?
59
+ * @examplePrompt Show me the family DSL
60
+ *
61
+ * # Example
62
+ * ```ts
63
+ * const { reference } = await snaptrude.design.family.getReference()
64
+ * ```
65
+ */
66
+ public abstract getReference(): PluginApiReturn<PluginFamilyReference>
67
+
68
+ /**
69
+ * Validate, compile and preview a family spec. Nothing is committed to the
70
+ * model or the library — call {@linkcode PluginDesignFamilyApi.place} or
71
+ * {@linkcode PluginDesignFamilyApi.create} for that.
72
+ *
73
+ * Safe to call repeatedly while iterating. On success, check `partCount` and
74
+ * `bbox` against what you intended before treating the family as correct — a
75
+ * facade that built 3 parts, or a 3 m screen reporting 40 m of height, is a
76
+ * visible bug the validator cannot catch.
77
+ *
78
+ * @param args The spec bundle, as `{ bundle }` or `{ spec }`
79
+ * @returns Build report, or `{ ok: false, errors }` with JSON-pointer paths
80
+ *
81
+ * @examplePrompt Make a louvre screen with adjustable blade count and tilt
82
+ * @examplePrompt Design a curtain wall panel family with 8 bays
83
+ * @examplePrompt Create a railing family I can adjust
84
+ *
85
+ * # Example
86
+ * ```ts
87
+ * const r = await snaptrude.design.family.prepare({ bundle })
88
+ * if (!r.ok) console.error(r.errors[0].path, r.errors[0].message)
89
+ * ```
90
+ */
91
+ public abstract prepare(
92
+ args: PluginDesignFamilyPrepareArgs,
93
+ ): PluginApiReturn<PluginFamilyPrepareResult>
94
+
95
+ /**
96
+ * Re-run the prepared family's recipe at new parameter values.
97
+ *
98
+ * Values are merged over the current ones and clamped to the parameter
99
+ * sheet's min/max, so a partial `{ bays: 6 }` is fine. The returned `changed`
100
+ * buckets are the host's own diff of what the geometry did — flexing a
101
+ * driving parameter and reporting them demonstrates the family is parametric.
102
+ *
103
+ * @param args The parameter values to change
104
+ * @returns The new build plus the geometry delta
105
+ *
106
+ * @examplePrompt Change it to 6 bays
107
+ * @examplePrompt Show me what happens with 20 blades
108
+ *
109
+ * # Example
110
+ * ```ts
111
+ * const { changed } = await snaptrude.design.family.flex({ values: { bays: 6 } })
112
+ * console.log(`removed ${changed.removed}, rebuilt ${changed.rebuilt}`)
113
+ * ```
114
+ */
115
+ public abstract flex(
116
+ args: PluginDesignFamilyFlexArgs,
117
+ ): PluginApiReturn<PluginFamilyFlexResult>
118
+
119
+ /**
120
+ * The prepared family's spec bundle, or `null` when nothing is prepared.
121
+ *
122
+ * @returns The draft bundle, or `null`
123
+ *
124
+ * # Example
125
+ * ```ts
126
+ * const bundle = await snaptrude.design.family.get()
127
+ * ```
128
+ */
129
+ public abstract get(): PluginApiReturn<PluginFamilyBundle | null>
130
+
131
+ /**
132
+ * Every parametric family registered in this session — native and imported.
133
+ *
134
+ * @returns One summary per family
135
+ *
136
+ * @examplePrompt What families are available?
137
+ *
138
+ * # Example
139
+ * ```ts
140
+ * const families = await snaptrude.design.family.list()
141
+ * ```
142
+ */
143
+ public abstract list(): PluginApiReturn<PluginFamilySummary[]>
144
+
145
+ /**
146
+ * Put a family into the model — either the prepared draft or any family from
147
+ * {@linkcode PluginDesignFamilyApi.list}.
148
+ *
149
+ * Two modes, chosen by whether you pass `position`:
150
+ *
151
+ * **With `position`** the component is created there and then, undoably. Use
152
+ * this when you know where it goes — you were given coordinates, or you are
153
+ * copying an existing instance. The returned `component` handle works with
154
+ * `design.transform.move` / `.rotate` and with
155
+ * {@linkcode PluginDesignFamilyApi.setParameters}.
156
+ *
157
+ * **Without `position`** it arms placement mode with a ghost on the cursor
158
+ * and returns immediately — no geometry yet. The USER clicks to drop it, so
159
+ * tell them to. Prefer this when the location is a judgement call.
160
+ *
161
+ * To COPY a placed component, place its family again at the new position with
162
+ * the same `values` — there is no separate copy call.
163
+ *
164
+ * @param args Which family, where, and at what parameter values
165
+ * @returns What was placed; `component` is present only in positioned mode
166
+ *
167
+ * @examplePrompt Place it in the model
168
+ * @examplePrompt Put a louvre screen at the origin
169
+ * @examplePrompt Copy that table two metres to the right
170
+ *
171
+ * # Example
172
+ * ```ts
173
+ * // positioned — geometry exists when this resolves
174
+ * const { component } = await snaptrude.design.family.place({
175
+ * id: "revit:gypsum-stud-partition~90ad72",
176
+ * position: { x: 0, y: 0, z: 0 },
177
+ * rotation: 90,
178
+ * })
179
+ * await snaptrude.design.transform.move([component], { x: 2, y: 0, z: 0 })
180
+ *
181
+ * // interactive — the user clicks
182
+ * await snaptrude.design.family.place()
183
+ * ```
184
+ */
185
+ public abstract place(
186
+ args?: PluginDesignFamilyPlaceArgs,
187
+ ): PluginApiReturn<PluginFamilyPlaceResult>
188
+
189
+ /**
190
+ * Read a placed component's current parameter values and its sheet.
191
+ *
192
+ * Use before {@linkcode PluginDesignFamilyApi.setParameters} so you change
193
+ * what is actually there: parameter KEYS are the family's own, not the
194
+ * label the user says, and a Revit-imported family carries parameters that
195
+ * do not drive geometry at all.
196
+ *
197
+ * @param args The component to read
198
+ * @returns Its definition, current values, and the parameter sheet
199
+ *
200
+ * @examplePrompt What size is that table?
201
+ * @examplePrompt Show me the parameters on this partition
202
+ *
203
+ * # Example
204
+ * ```ts
205
+ * const { values, parameters } = await snaptrude.design.family.getParameters({ component })
206
+ * ```
207
+ */
208
+ public abstract getParameters(
209
+ args: PluginDesignFamilyGetParametersArgs,
210
+ ): PluginApiReturn<PluginFamilyInstanceParameters | null>
211
+
212
+ /**
213
+ * Change a placed component's parameters and rebuild its geometry in place.
214
+ *
215
+ * Partial: pass only what changes. The component keeps its position,
216
+ * rotation and identity — this is an edit, not a replace, and it is undoable.
217
+ *
218
+ * Only parameters with `drivesGeometry` actually move the mesh. Setting one
219
+ * that does not is accepted and stored (it round-trips to Revit) but nothing
220
+ * visible happens — say so rather than claiming a change the user cannot see.
221
+ *
222
+ * @param args The component and the values to change
223
+ * @returns The values now in effect
224
+ *
225
+ * @examplePrompt Make that table seat 8
226
+ * @examplePrompt Change the stud spacing to 400
227
+ *
228
+ * # Example
229
+ * ```ts
230
+ * await snaptrude.design.family.setParameters({ component, values: { seats: 8 } })
231
+ * ```
232
+ */
233
+ public abstract setParameters(
234
+ args: PluginDesignFamilySetParametersArgs,
235
+ ): PluginApiReturn<PluginFamilyInstanceParameters>
236
+
237
+ /**
238
+ * Commit the prepared bundle to the project's parametric-definition library,
239
+ * so it survives the session and appears in the Families panel.
240
+ *
241
+ * @param args Optional library name and team scope
242
+ * @returns The catalogued definition's id and version
243
+ *
244
+ * @examplePrompt Save this as a family called Vertical Louvre
245
+ * @examplePrompt Add it to my library
246
+ *
247
+ * # Example
248
+ * ```ts
249
+ * const { definitionId } = await snaptrude.design.family.create({ name: "Louvre Screen" })
250
+ * ```
251
+ */
252
+ public abstract create(
253
+ args?: PluginDesignFamilyCreateArgs,
254
+ ): PluginApiReturn<PluginFamilyCreateResult>
255
+ }
256
+
257
+ // ---------------------------------------------------------------------------
258
+ // Result types
259
+ // ---------------------------------------------------------------------------
260
+
261
+ /** The family-spec DSL reference returned by `getReference`. */
262
+ export interface PluginFamilyReference {
263
+ /** Grammar, op table, expression whitelist, repair contract, worked example. */
264
+ reference: string
265
+ }
266
+
267
+ /**
268
+ * A family spec bundle. `root` is the family; `deps` carries every spec
269
+ * reachable through an `instance` op, keyed by spec id, so a saved family is
270
+ * self-contained and reloads anywhere.
271
+ *
272
+ * The internal shape of a spec is documented by
273
+ * {@linkcode PluginDesignFamilyApi.getReference}, not by these types — it is a
274
+ * data DSL whose grammar changes independently of this API surface.
275
+ */
276
+ export interface PluginFamilyBundle {
277
+ root: Record<string, unknown>
278
+ deps?: Record<string, Record<string, unknown>>
279
+ }
280
+
281
+ /** Axis-aligned extents of a built family. Integer millimetres, +Y up. */
282
+ export interface PluginFamilyBBox {
283
+ min: [number, number, number]
284
+ max: [number, number, number]
285
+ /** `[width, height, depth]` in millimetres. */
286
+ size: [number, number, number]
287
+ }
288
+
289
+ /** One row of a family's parameter sheet. */
290
+ export interface PluginFamilyParameter {
291
+ key: string
292
+ label: string
293
+ type: "length" | "integer" | "enum" | "text" | "boolean"
294
+ /** Current value. `length`/`integer` are numbers; the rest are strings. */
295
+ value: string | number
296
+ default: string | number
297
+ /**
298
+ * Whether this parameter actually drives geometry — INFERRED by the host from
299
+ * which names the spec's expressions reference. `false` means the value is
300
+ * stored and round-tripped but moves nothing.
301
+ */
302
+ drivesGeometry: boolean
303
+ min?: number
304
+ max?: number
305
+ options?: readonly string[]
306
+ }
307
+
308
+ /**
309
+ * A validation diagnostic. `path` is a JSON pointer into the submitted bundle —
310
+ * fix that node and re-`prepare`.
311
+ */
312
+ export interface PluginFamilyDiagnostic {
313
+ /** JSON pointer, e.g. `"/root/geometry/2/body/0/w"`. */
314
+ path: string
315
+ code:
316
+ | "schema"
317
+ | "bad-expression"
318
+ | "unknown-name"
319
+ | "unknown-def"
320
+ | "cycle"
321
+ | "duplicate-name"
322
+ | "unbounded-repeat"
323
+ | "depth"
324
+ | "bad-dimension"
325
+ message: string
326
+ hint?: string
327
+ }
328
+
329
+ /** What `prepare` reports. */
330
+ export interface PluginFamilyPrepareResult {
331
+ /** `false` means the spec was rejected — read `errors`, fix, re-prepare. */
332
+ ok: boolean
333
+ familyId?: string
334
+ version?: number
335
+ label?: string
336
+ /** How many parts the family built. Sanity-check against intent. */
337
+ partCount?: number
338
+ /** Extents in millimetres. Sanity-check against intent. */
339
+ bbox?: PluginFamilyBBox
340
+ evalMs?: number
341
+ parameters?: PluginFamilyParameter[]
342
+ /** Computed quantities, when the spec declares a `takeoff` block. */
343
+ takeoff?: Record<string, number | string>
344
+ /** The first few part names — enough to check the naming came out right. */
345
+ sampleParts?: string[]
346
+ errors: PluginFamilyDiagnostic[]
347
+ warnings: PluginFamilyDiagnostic[]
348
+ /** Set when the bundle validated but threw while building. */
349
+ error?: string
350
+ }
351
+
352
+ /**
353
+ * The host's diff of what a flex did to the geometry. This is the evidence that
354
+ * a family is parametric.
355
+ */
356
+ export interface PluginFamilyChangeBuckets {
357
+ added: number
358
+ removed: number
359
+ moved: number
360
+ rebuilt: number
361
+ addedNames: string[]
362
+ removedNames: string[]
363
+ }
364
+
365
+ /** What `flex` reports. */
366
+ export interface PluginFamilyFlexResult {
367
+ ok: boolean
368
+ /** The RESOLVED values after merge + clamping — not necessarily what was sent. */
369
+ values?: Record<string, number | string>
370
+ partCount?: number
371
+ bbox?: PluginFamilyBBox
372
+ evalMs?: number
373
+ changed?: PluginFamilyChangeBuckets
374
+ takeoff?: Record<string, number | string>
375
+ error?: string
376
+ }
377
+
378
+ /** One family available to place — from the session registry or the catalog. */
379
+ export interface PluginFamilySummary {
380
+ id: string
381
+ version: number
382
+ label: string
383
+ category?: string
384
+ /** Number of rows on the family's parameter sheet. */
385
+ parameters: number
386
+ /**
387
+ * Where the family came from, which decides how far you can edit it.
388
+ *
389
+ * `"native"` — authored from a JSON spec through this API. Its recipe is
390
+ * data, so every parameter genuinely re-runs the geometry.
391
+ *
392
+ * `"revit"` — imported from a Revit family. Parameters exist and are
393
+ * editable, but only those the importer could bind to geometry actually
394
+ * change the mesh; the rest are carried for round-tripping. Check
395
+ * `drivesGeometry` on the parameter before promising the user a change.
396
+ */
397
+ kind: "native" | "revit"
398
+ }
399
+
400
+ /** What `place` reports. */
401
+ export interface PluginFamilyPlaceResult {
402
+ ok: boolean
403
+ familyId?: string
404
+ version?: number
405
+ /**
406
+ * The created component — present ONLY when `position` was given. In
407
+ * interactive mode nothing exists yet, so there is nothing to hand back;
408
+ * the user has not clicked.
409
+ */
410
+ component?: ComponentHandle
411
+ error?: string
412
+ }
413
+
414
+ /** A placed component's parameter state, from `getParameters` / `setParameters`. */
415
+ export interface PluginFamilyInstanceParameters {
416
+ /** The definition this instance is pinned to. */
417
+ familyId: string
418
+ version: number
419
+ label: string
420
+ /** Current values, keyed by parameter key. */
421
+ values: Record<string, number | string>
422
+ /** The sheet: what each key means, its bounds, and whether it moves geometry. */
423
+ parameters: PluginFamilyParameter[]
424
+ }
425
+
426
+ /** What `create` reports. */
427
+ export interface PluginFamilyCreateResult {
428
+ ok: boolean
429
+ definitionId?: string
430
+ version?: number
431
+ guid?: string
432
+ error?: string
433
+ }
434
+
435
+ // ---------------------------------------------------------------------------
436
+ // Argument schemas
437
+ // ---------------------------------------------------------------------------
438
+
439
+ /**
440
+ * A spec bundle as it crosses the boundary: `root` plus optional `deps`.
441
+ *
442
+ * Loose by design — the spec grammar is a data DSL validated by the host's own
443
+ * validator, which returns JSON-pointer diagnostics far more useful than a Zod
444
+ * shape error. This schema only guarantees the envelope is an object.
445
+ */
446
+ export const PluginFamilyBundleSchema = z.object({
447
+ root: z.record(z.string(), z.unknown()),
448
+ deps: z.record(z.string(), z.record(z.string(), z.unknown())).optional(),
449
+ })
450
+
451
+ /**
452
+ * Arguments for {@linkcode PluginDesignFamilyApi.prepare}.
453
+ *
454
+ * | Property | Type | Description |
455
+ * |---|---|---|
456
+ * | `bundle` | {@linkcode PluginFamilyBundle} | The family spec bundle |
457
+ * | `spec` | {@linkcode PluginFamilyBundle} | Alias for `bundle` |
458
+ *
459
+ * Exactly one of `bundle` / `spec` is required. A bare `FamilySpec` (no `root`
460
+ * wrapper) is also accepted by the host and wrapped for the caller.
461
+ */
462
+ export const PluginDesignFamilyPrepareArgs = z.object({
463
+ bundle: PluginFamilyBundleSchema.optional(),
464
+ spec: PluginFamilyBundleSchema.optional(),
465
+ })
466
+ export type PluginDesignFamilyPrepareArgs = z.infer<typeof PluginDesignFamilyPrepareArgs>
467
+
468
+ /**
469
+ * Arguments for {@linkcode PluginDesignFamilyApi.flex}.
470
+ *
471
+ * | Property | Type | Description |
472
+ * |---|---|---|
473
+ * | `values` | `Record<string, number \| string>` | Parameter values to change (partial) |
474
+ */
475
+ export const PluginDesignFamilyFlexArgs = z.object({
476
+ values: z.record(z.string(), z.union([z.number(), z.string()])),
477
+ })
478
+ export type PluginDesignFamilyFlexArgs = z.infer<typeof PluginDesignFamilyFlexArgs>
479
+
480
+ /**
481
+ * Arguments for {@linkcode PluginDesignFamilyApi.create}.
482
+ *
483
+ * | Property | Type | Description |
484
+ * |---|---|---|
485
+ * | `name` | `string` | Library name; defaults to the spec's own label |
486
+ * | `teamId` | `string` | Team library to save into; omit for personal |
487
+ */
488
+ export const PluginDesignFamilyCreateArgs = z.object({
489
+ name: z.string().optional(),
490
+ teamId: z.string().optional(),
491
+ })
492
+ export type PluginDesignFamilyCreateArgs = z.infer<typeof PluginDesignFamilyCreateArgs>
493
+
494
+ /**
495
+ * Arguments for {@linkcode PluginDesignFamilyApi.place}.
496
+ *
497
+ * | Property | Type | Description |
498
+ * |---|---|---|
499
+ * | `id` | `string` | Family to place, from {@linkcode PluginDesignFamilyApi.list}. Omit to place the prepared draft |
500
+ * | `version` | `number` | Exact version; defaults to the newest known |
501
+ * | `position` | `{ x, y, z }` | Place HERE, without user interaction. Omit to arm the cursor instead |
502
+ * | `rotation` | `number` | Yaw in degrees about +Y. Only with `position` |
503
+ * | `values` | `Record<string, number \| string>` | Parameter values for THIS instance |
504
+ * | `storey` | `number` | Storey to place on; defaults to the active one |
505
+ */
506
+ export const PluginDesignFamilyPlaceArgs = z.object({
507
+ id: z.string().optional(),
508
+ version: z.number().int().positive().optional(),
509
+ position: Vec3Components.optional(),
510
+ rotation: z.number().optional(),
511
+ values: z.record(z.string(), z.union([z.number(), z.string()])).optional(),
512
+ storey: z.number().int().optional(),
513
+ })
514
+ export type PluginDesignFamilyPlaceArgs = z.infer<typeof PluginDesignFamilyPlaceArgs>
515
+
516
+ /**
517
+ * Arguments for {@linkcode PluginDesignFamilyApi.getParameters}.
518
+ *
519
+ * | Property | Type | Description |
520
+ * |---|---|---|
521
+ * | `component` | {@linkcode ComponentHandle} | A placed parametric component |
522
+ */
523
+ export const PluginDesignFamilyGetParametersArgs = z.object({
524
+ component: ComponentHandle,
525
+ })
526
+ export type PluginDesignFamilyGetParametersArgs = z.infer<
527
+ typeof PluginDesignFamilyGetParametersArgs
528
+ >
529
+
530
+ /**
531
+ * Arguments for {@linkcode PluginDesignFamilyApi.setParameters}.
532
+ *
533
+ * | Property | Type | Description |
534
+ * |---|---|---|
535
+ * | `component` | {@linkcode ComponentHandle} | A placed parametric component |
536
+ * | `values` | `Record<string, number \| string>` | Values to change (partial) |
537
+ */
538
+ export const PluginDesignFamilySetParametersArgs = z.object({
539
+ component: ComponentHandle,
540
+ values: z.record(z.string(), z.union([z.number(), z.string()])),
541
+ })
542
+ export type PluginDesignFamilySetParametersArgs = z.infer<
543
+ typeof PluginDesignFamilySetParametersArgs
544
+ >