@snaptrude/plugin-core 0.2.9 → 0.5.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 (269) hide show
  1. package/AGENTS.md +128 -50
  2. package/CHANGELOG.md +52 -6
  3. package/api-manifest.full.json +3999 -0
  4. package/api-manifest.json +3845 -0
  5. package/dist/api/core/buildings.d.ts +427 -0
  6. package/dist/api/core/buildings.d.ts.map +1 -0
  7. package/dist/api/core/comment/index.d.ts +230 -0
  8. package/dist/api/core/comment/index.d.ts.map +1 -0
  9. package/dist/api/core/geom/create/index.d.ts +247 -0
  10. package/dist/api/core/geom/create/index.d.ts.map +1 -0
  11. package/dist/api/core/geom/delete/index.d.ts +72 -0
  12. package/dist/api/core/geom/delete/index.d.ts.map +1 -0
  13. package/dist/api/core/geom/index.d.ts +24 -23
  14. package/dist/api/core/geom/index.d.ts.map +1 -1
  15. package/dist/api/core/geom/query/arc.d.ts +169 -0
  16. package/dist/api/core/geom/query/arc.d.ts.map +1 -0
  17. package/dist/api/core/geom/query/brep.d.ts +402 -0
  18. package/dist/api/core/geom/query/brep.d.ts.map +1 -0
  19. package/dist/api/core/geom/query/circle.d.ts +378 -0
  20. package/dist/api/core/geom/query/circle.d.ts.map +1 -0
  21. package/dist/api/core/geom/query/contour.d.ts +450 -0
  22. package/dist/api/core/geom/query/contour.d.ts.map +1 -0
  23. package/dist/api/core/geom/query/curve.d.ts +918 -0
  24. package/dist/api/core/geom/query/curve.d.ts.map +1 -0
  25. package/dist/api/core/geom/query/edge.d.ts +128 -0
  26. package/dist/api/core/geom/query/edge.d.ts.map +1 -0
  27. package/dist/api/core/geom/query/face.d.ts +363 -0
  28. package/dist/api/core/geom/query/face.d.ts.map +1 -0
  29. package/dist/api/core/geom/query/halfedge.d.ts +206 -0
  30. package/dist/api/core/geom/query/halfedge.d.ts.map +1 -0
  31. package/dist/api/core/geom/query/index.d.ts +61 -0
  32. package/dist/api/core/geom/query/index.d.ts.map +1 -0
  33. package/dist/api/core/geom/query/profile.d.ts +410 -0
  34. package/dist/api/core/geom/query/profile.d.ts.map +1 -0
  35. package/dist/api/core/geom/query/vertex.d.ts +187 -0
  36. package/dist/api/core/geom/query/vertex.d.ts.map +1 -0
  37. package/dist/api/core/geom/update/contour.d.ts +272 -0
  38. package/dist/api/core/geom/update/contour.d.ts.map +1 -0
  39. package/dist/api/core/geom/update/curve.d.ts +180 -0
  40. package/dist/api/core/geom/update/curve.d.ts.map +1 -0
  41. package/dist/api/core/geom/update/index.d.ts +27 -0
  42. package/dist/api/core/geom/update/index.d.ts.map +1 -0
  43. package/dist/api/core/geom/update/profile.d.ts +329 -0
  44. package/dist/api/core/geom/update/profile.d.ts.map +1 -0
  45. package/dist/api/core/groups.d.ts +485 -0
  46. package/dist/api/core/groups.d.ts.map +1 -0
  47. package/dist/api/core/history/index.d.ts +78 -0
  48. package/dist/api/core/history/index.d.ts.map +1 -0
  49. package/dist/api/core/index.d.ts +46 -1
  50. package/dist/api/core/index.d.ts.map +1 -1
  51. package/dist/api/core/layers.d.ts +402 -0
  52. package/dist/api/core/layers.d.ts.map +1 -0
  53. package/dist/api/core/math/quat.d.ts +111 -128
  54. package/dist/api/core/math/quat.d.ts.map +1 -1
  55. package/dist/api/core/math/vec3.d.ts +120 -102
  56. package/dist/api/core/math/vec3.d.ts.map +1 -1
  57. package/dist/api/core/project/index.d.ts +399 -0
  58. package/dist/api/core/project/index.d.ts.map +1 -0
  59. package/dist/api/core/tags.d.ts +755 -0
  60. package/dist/api/core/tags.d.ts.map +1 -0
  61. package/dist/api/core/units/index.d.ts +175 -0
  62. package/dist/api/core/units/index.d.ts.map +1 -0
  63. package/dist/api/core/zoom/index.d.ts +45 -0
  64. package/dist/api/core/zoom/index.d.ts.map +1 -0
  65. package/dist/api/design/boolean/index.d.ts +168 -0
  66. package/dist/api/design/boolean/index.d.ts.map +1 -0
  67. package/dist/api/design/create/index.d.ts +828 -0
  68. package/dist/api/design/create/index.d.ts.map +1 -0
  69. package/dist/api/design/delete/index.d.ts +63 -0
  70. package/dist/api/design/delete/index.d.ts.map +1 -0
  71. package/dist/api/design/doors/index.d.ts +268 -0
  72. package/dist/api/design/doors/index.d.ts.map +1 -0
  73. package/dist/api/design/edit/index.d.ts +49 -0
  74. package/dist/api/design/edit/index.d.ts.map +1 -0
  75. package/dist/api/design/erase/index.d.ts +160 -0
  76. package/dist/api/design/erase/index.d.ts.map +1 -0
  77. package/dist/api/design/furniture/index.d.ts +123 -0
  78. package/dist/api/design/furniture/index.d.ts.map +1 -0
  79. package/dist/api/design/index.d.ts +153 -0
  80. package/dist/api/design/index.d.ts.map +1 -0
  81. package/dist/api/design/lock.d.ts +41 -0
  82. package/dist/api/design/lock.d.ts.map +1 -0
  83. package/dist/api/design/materials/index.d.ts +297 -0
  84. package/dist/api/design/materials/index.d.ts.map +1 -0
  85. package/dist/api/design/query/geometry/index.d.ts +140 -0
  86. package/dist/api/design/query/geometry/index.d.ts.map +1 -0
  87. package/dist/api/design/query/index.d.ts +1011 -0
  88. package/dist/api/design/query/index.d.ts.map +1 -0
  89. package/dist/api/design/query/spaces.d.ts +221 -0
  90. package/dist/api/design/query/spaces.d.ts.map +1 -0
  91. package/dist/api/design/selection/index.d.ts +138 -0
  92. package/dist/api/design/selection/index.d.ts.map +1 -0
  93. package/dist/api/design/shared.d.ts +38 -0
  94. package/dist/api/design/shared.d.ts.map +1 -0
  95. package/dist/api/design/transform/index.d.ts +87 -0
  96. package/dist/api/design/transform/index.d.ts.map +1 -0
  97. package/dist/api/design/update/index.d.ts +178 -0
  98. package/dist/api/design/update/index.d.ts.map +1 -0
  99. package/dist/api/design/windows/index.d.ts +189 -0
  100. package/dist/api/design/windows/index.d.ts.map +1 -0
  101. package/dist/api/entity/buildableEnvelope.d.ts +51 -23
  102. package/dist/api/entity/buildableEnvelope.d.ts.map +1 -1
  103. package/dist/api/entity/department.d.ts +0 -98
  104. package/dist/api/entity/department.d.ts.map +1 -1
  105. package/dist/api/entity/index.d.ts +4 -9
  106. package/dist/api/entity/index.d.ts.map +1 -1
  107. package/dist/api/entity/referenceLine.d.ts +49 -106
  108. package/dist/api/entity/referenceLine.d.ts.map +1 -1
  109. package/dist/api/entity/space.d.ts +76 -828
  110. package/dist/api/entity/space.d.ts.map +1 -1
  111. package/dist/api/entity/story.d.ts +47 -37
  112. package/dist/api/entity/story.d.ts.map +1 -1
  113. package/dist/api/index.d.ts +17 -17
  114. package/dist/api/index.d.ts.map +1 -1
  115. package/dist/api/presentation/aiInspiration.d.ts +440 -0
  116. package/dist/api/presentation/aiInspiration.d.ts.map +1 -0
  117. package/dist/api/presentation/diagrams.d.ts +81 -0
  118. package/dist/api/presentation/diagrams.d.ts.map +1 -0
  119. package/dist/api/presentation/import.d.ts +113 -0
  120. package/dist/api/presentation/import.d.ts.map +1 -0
  121. package/dist/api/presentation/index.d.ts +46 -0
  122. package/dist/api/presentation/index.d.ts.map +1 -0
  123. package/dist/api/presentation/sheets.d.ts +176 -0
  124. package/dist/api/presentation/sheets.d.ts.map +1 -0
  125. package/dist/api/presentation/views.d.ts +296 -0
  126. package/dist/api/presentation/views.d.ts.map +1 -0
  127. package/dist/api/program/adjacency.d.ts +155 -0
  128. package/dist/api/program/adjacency.d.ts.map +1 -0
  129. package/dist/api/program/areas.d.ts +360 -0
  130. package/dist/api/program/areas.d.ts.map +1 -0
  131. package/dist/api/program/classification.d.ts +135 -0
  132. package/dist/api/program/classification.d.ts.map +1 -0
  133. package/dist/api/program/cores.d.ts +174 -0
  134. package/dist/api/program/cores.d.ts.map +1 -0
  135. package/dist/api/program/departments.d.ts +431 -0
  136. package/dist/api/program/departments.d.ts.map +1 -0
  137. package/dist/api/program/index.d.ts +69 -0
  138. package/dist/api/program/index.d.ts.map +1 -0
  139. package/dist/api/program/layout.d.ts +63 -0
  140. package/dist/api/program/layout.d.ts.map +1 -0
  141. package/dist/api/program/metrics.d.ts +108 -0
  142. package/dist/api/program/metrics.d.ts.map +1 -0
  143. package/dist/api/program/site.d.ts +367 -0
  144. package/dist/api/program/site.d.ts.map +1 -0
  145. package/dist/api/program/spreadsheet.d.ts +2041 -0
  146. package/dist/api/program/spreadsheet.d.ts.map +1 -0
  147. package/dist/handles.d.ts +138 -0
  148. package/dist/handles.d.ts.map +1 -0
  149. package/dist/host-utils.d.ts +7 -5
  150. package/dist/host-utils.d.ts.map +1 -1
  151. package/dist/index.cjs +3897 -1542
  152. package/dist/index.cjs.map +1 -1
  153. package/dist/index.d.ts +1 -0
  154. package/dist/index.d.ts.map +1 -1
  155. package/dist/index.js +3326 -1462
  156. package/dist/index.js.map +1 -1
  157. package/package.json +6 -2
  158. package/scripts/generate-manifest.mjs +193 -0
  159. package/scripts/generate-manifest.test.mjs +193 -0
  160. package/src/api/core/buildings.ts +485 -0
  161. package/src/api/core/comment/index.ts +258 -0
  162. package/src/api/core/geom/create/index.ts +293 -0
  163. package/src/api/core/geom/delete/index.ts +78 -0
  164. package/src/api/core/geom/index.ts +24 -23
  165. package/src/api/core/geom/query/arc.ts +169 -0
  166. package/src/api/core/geom/query/brep.ts +444 -0
  167. package/src/api/core/geom/query/circle.ts +404 -0
  168. package/src/api/core/geom/query/contour.ts +540 -0
  169. package/src/api/core/geom/query/curve.ts +1078 -0
  170. package/src/api/core/geom/query/edge.ts +130 -0
  171. package/src/api/core/geom/query/face.ts +403 -0
  172. package/src/api/core/geom/query/halfedge.ts +210 -0
  173. package/src/api/core/geom/query/index.ts +63 -0
  174. package/src/api/core/geom/query/profile.ts +473 -0
  175. package/src/api/core/geom/query/vertex.ts +205 -0
  176. package/src/api/core/geom/update/contour.ts +315 -0
  177. package/src/api/core/geom/update/curve.ts +209 -0
  178. package/src/api/core/geom/update/index.ts +29 -0
  179. package/src/api/core/geom/update/profile.ts +377 -0
  180. package/src/api/core/groups.ts +521 -0
  181. package/src/api/core/history/index.ts +84 -0
  182. package/src/api/core/index.ts +46 -1
  183. package/src/api/core/layers.ts +333 -0
  184. package/src/api/core/math/quat.ts +112 -235
  185. package/src/api/core/math/vec3.ts +124 -159
  186. package/src/api/core/project/index.ts +418 -0
  187. package/src/api/core/tags.ts +808 -0
  188. package/src/api/core/units/index.ts +164 -0
  189. package/src/api/core/zoom/index.ts +47 -0
  190. package/src/api/design/boolean/index.ts +179 -0
  191. package/src/api/design/create/index.ts +886 -0
  192. package/src/api/design/delete/index.ts +67 -0
  193. package/src/api/design/doors/index.ts +285 -0
  194. package/src/api/design/edit/index.ts +54 -0
  195. package/src/api/design/erase/index.ts +151 -0
  196. package/src/api/design/furniture/index.ts +130 -0
  197. package/src/api/design/index.ts +162 -0
  198. package/src/api/design/lock.ts +42 -0
  199. package/src/api/design/materials/index.ts +301 -0
  200. package/src/api/design/query/geometry/index.ts +166 -0
  201. package/src/api/design/query/index.ts +937 -0
  202. package/src/api/design/query/spaces.ts +132 -0
  203. package/src/api/design/selection/index.ts +144 -0
  204. package/src/api/design/shared.ts +40 -0
  205. package/src/api/design/transform/index.ts +93 -0
  206. package/src/api/design/update/index.ts +117 -0
  207. package/src/api/design/windows/index.ts +207 -0
  208. package/src/api/entity/buildableEnvelope.ts +64 -23
  209. package/src/api/entity/department.ts +0 -113
  210. package/src/api/entity/index.ts +4 -9
  211. package/src/api/entity/referenceLine.ts +50 -38
  212. package/src/api/entity/space.ts +84 -440
  213. package/src/api/entity/story.ts +53 -42
  214. package/src/api/index.ts +17 -17
  215. package/src/api/presentation/aiInspiration.ts +362 -0
  216. package/src/api/presentation/diagrams.ts +84 -0
  217. package/src/api/presentation/import.ts +112 -0
  218. package/src/api/presentation/index.ts +48 -0
  219. package/src/api/presentation/sheets.ts +198 -0
  220. package/src/api/presentation/views.ts +303 -0
  221. package/src/api/program/adjacency.ts +164 -0
  222. package/src/api/program/areas.ts +335 -0
  223. package/src/api/program/classification.ts +138 -0
  224. package/src/api/program/cores.ts +171 -0
  225. package/src/api/program/departments.ts +465 -0
  226. package/src/api/program/index.ts +71 -0
  227. package/src/api/program/layout.ts +68 -0
  228. package/src/api/program/metrics.ts +120 -0
  229. package/src/api/program/site.ts +326 -0
  230. package/src/api/program/spreadsheet.ts +2075 -0
  231. package/src/handles.ts +148 -0
  232. package/src/host-utils.ts +10 -6
  233. package/src/index.ts +1 -0
  234. package/dist/api/core/geom/arc.d.ts +0 -81
  235. package/dist/api/core/geom/arc.d.ts.map +0 -1
  236. package/dist/api/core/geom/curve.d.ts +0 -70
  237. package/dist/api/core/geom/curve.d.ts.map +0 -1
  238. package/dist/api/core/geom/line.d.ts +0 -56
  239. package/dist/api/core/geom/line.d.ts.map +0 -1
  240. package/dist/api/core/geom/profile.d.ts +0 -121
  241. package/dist/api/core/geom/profile.d.ts.map +0 -1
  242. package/dist/api/documentation/aiInspiration.d.ts +0 -2155
  243. package/dist/api/documentation/aiInspiration.d.ts.map +0 -1
  244. package/dist/api/documentation/index.d.ts +0 -13
  245. package/dist/api/documentation/index.d.ts.map +0 -1
  246. package/dist/api/tools/copy.d.ts +0 -59
  247. package/dist/api/tools/copy.d.ts.map +0 -1
  248. package/dist/api/tools/index.d.ts +0 -29
  249. package/dist/api/tools/index.d.ts.map +0 -1
  250. package/dist/api/tools/offset.d.ts +0 -43
  251. package/dist/api/tools/offset.d.ts.map +0 -1
  252. package/dist/api/tools/selection.d.ts +0 -48
  253. package/dist/api/tools/selection.d.ts.map +0 -1
  254. package/dist/api/tools/transform.d.ts +0 -114
  255. package/dist/api/tools/transform.d.ts.map +0 -1
  256. package/dist/api/units/index.d.ts +0 -163
  257. package/dist/api/units/index.d.ts.map +0 -1
  258. package/src/api/core/geom/arc.ts +0 -70
  259. package/src/api/core/geom/curve.ts +0 -41
  260. package/src/api/core/geom/line.ts +0 -53
  261. package/src/api/core/geom/profile.ts +0 -94
  262. package/src/api/documentation/aiInspiration.ts +0 -871
  263. package/src/api/documentation/index.ts +0 -15
  264. package/src/api/tools/copy.ts +0 -55
  265. package/src/api/tools/index.ts +0 -35
  266. package/src/api/tools/offset.ts +0 -43
  267. package/src/api/tools/selection.ts +0 -51
  268. package/src/api/tools/transform.ts +0 -117
  269. package/src/api/units/index.ts +0 -163
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/api/core/math/vec3.ts","../src/api/core/math/quat.ts","../src/api/core/math/index.ts","../src/api/core/geom/line.ts","../src/api/core/geom/arc.ts","../src/api/core/geom/curve.ts","../src/api/core/geom/profile.ts","../src/api/core/geom/index.ts","../src/api/core/index.ts","../src/api/documentation/aiInspiration.ts","../src/api/documentation/index.ts","../src/api/entity/buildableEnvelope.ts","../src/api/entity/department.ts","../src/api/entity/referenceLine.ts","../src/api/entity/space.ts","../src/api/entity/story.ts","../src/api/entity/index.ts","../src/api/tools/copy.ts","../src/api/tools/offset.ts","../src/api/tools/selection.ts","../src/api/tools/transform.ts","../src/api/tools/index.ts","../src/api/units/index.ts","../src/api/index.ts"],"sourcesContent":["import * as z from \"zod\"\n\n/**\n * 3D vector operations for positions, directions, and displacements.\n *\n * All methods are **pure** — they return new {@linkcode PVec3} values\n * without mutating the inputs.\n *\n * Accessed via `snaptrude.core.math.vec3`.\n */\nexport abstract class PluginVec3Api {\n constructor() {}\n\n /**\n * Create a new 3D vector.\n *\n * @param x - The X component\n * @param y - The Y component\n * @param z - The Z component\n * @returns A new {@linkcode PVec3}\n *\n * # Example\n * ```ts\n * const position = snaptrude.core.math.vec3.new(1, 2, 3)\n * // { x: 1, y: 2, z: 3 }\n * ```\n */\n new(x: number, y: number, z: number): PVec3 {\n return { x, y, z }\n }\n\n /**\n * Add two vectors component-wise.\n *\n * @param a - First vector\n * @param b - Second vector\n * @returns A new {@linkcode PVec3} where each component is `a[i] + b[i]`\n */\n add(a: PVec3, b: PVec3): PVec3 {\n return { x: a.x + b.x, y: a.y + b.y, z: a.z + b.z }\n }\n\n /**\n * Subtract vector {@linkcode b} from vector {@linkcode a} component-wise.\n *\n * @param a - Vector to subtract from\n * @param b - Vector to subtract\n * @returns A new {@linkcode PVec3} where each component is `a[i] - b[i]`\n */\n subtract(a: PVec3, b: PVec3): PVec3 {\n return { x: a.x - b.x, y: a.y - b.y, z: a.z - b.z }\n }\n\n /**\n * Scale a vector by a scalar value.\n *\n * @param v - The vector to scale\n * @param scalar - The scalar multiplier\n * @returns A new {@linkcode PVec3} where each component is `v[i] * scalar`\n */\n scale(v: PVec3, scalar: number): PVec3 {\n return { x: v.x * scalar, y: v.y * scalar, z: v.z * scalar }\n }\n\n /**\n * Compute the dot product of two vectors.\n *\n * The dot product equals `|a| * |b| * cos(θ)` where `θ` is the angle\n * between the vectors. Useful for checking orthogonality (result = 0)\n * or projection.\n *\n * @param a - First vector\n * @param b - Second vector\n * @returns The scalar dot product\n */\n dot(a: PVec3, b: PVec3): number {\n return a.x * b.x + a.y * b.y + a.z * b.z\n }\n\n /**\n * Compute the cross product of two vectors.\n *\n * The result is a vector perpendicular to both inputs, with magnitude\n * equal to the area of the parallelogram they span. Useful for computing\n * surface normals.\n *\n * @param a - First vector\n * @param b - Second vector\n * @returns A new {@linkcode PVec3} perpendicular to both {@linkcode a} and {@linkcode b}\n */\n cross(a: PVec3, b: PVec3): PVec3 {\n return {\n x: a.y * b.z - a.z * b.y,\n y: a.z * b.x - a.x * b.z,\n z: a.x * b.y - a.y * b.x,\n }\n }\n\n /**\n * Compute the length (magnitude) of a vector.\n *\n * @param v - The vector\n * @returns The Euclidean length `√(x² + y² + z²)`\n */\n length(v: PVec3): number {\n return Math.sqrt(v.x * v.x + v.y * v.y + v.z * v.z)\n }\n\n /**\n * Compute the squared length of a vector.\n *\n * Avoids the `sqrt` call — prefer this over {@linkcode PluginVec3Api.length}\n * when comparing relative magnitudes.\n *\n * @param v - The vector\n * @returns The squared length `x² + y² + z²`\n */\n lengthSquared(v: PVec3): number {\n return v.x * v.x + v.y * v.y + v.z * v.z\n }\n\n /**\n * Normalize a vector to unit length.\n *\n * @param v - The vector to normalize\n * @returns A new unit-length {@linkcode PVec3} in the same direction,\n * or a zero vector `(0, 0, 0)` if the input has zero length\n */\n normalize(v: PVec3): PVec3 {\n const len = this.length(v)\n if (len === 0) return { x: 0, y: 0, z: 0 }\n return { x: v.x / len, y: v.y / len, z: v.z / len }\n }\n\n /**\n * Compute the Euclidean distance between two points.\n *\n * @param a - First point\n * @param b - Second point\n * @returns The distance `|a - b|`\n */\n distance(a: PVec3, b: PVec3): number {\n return this.length(this.subtract(a, b))\n }\n\n /**\n * Linearly interpolate between two vectors.\n *\n * @param a - Start vector (returned when `t = 0`)\n * @param b - End vector (returned when `t = 1`)\n * @param t - Interpolation factor, typically in `[0, 1]`\n * @returns A new {@linkcode PVec3} at `a + (b - a) * t`\n */\n lerp(a: PVec3, b: PVec3, t: number): PVec3 {\n return {\n x: a.x + (b.x - a.x) * t,\n y: a.y + (b.y - a.y) * t,\n z: a.z + (b.z - a.z) * t,\n }\n }\n\n /**\n * Negate a vector (reverse its direction).\n *\n * @param v - The vector to negate\n * @returns A new {@linkcode PVec3} with all components negated\n */\n negate(v: PVec3): PVec3 {\n return { x: -v.x, y: -v.y, z: -v.z }\n }\n\n /**\n * Check if two vectors are exactly equal (strict equality per component).\n *\n * For floating-point comparisons, prefer {@linkcode PluginVec3Api.equalsApprox}.\n *\n * @param a - First vector\n * @param b - Second vector\n * @returns `true` if all components match exactly\n */\n equals(a: PVec3, b: PVec3): boolean {\n return a.x === b.x && a.y === b.y && a.z === b.z\n }\n\n /**\n * Check if two vectors are approximately equal within a tolerance.\n *\n * @param a - First vector\n * @param b - Second vector\n * @param epsilon - Maximum allowed difference per component (default `1e-6`)\n * @returns `true` if `|a[i] - b[i]| < epsilon` for all components\n */\n equalsApprox(a: PVec3, b: PVec3, epsilon: number = 1e-6): boolean {\n return (\n Math.abs(a.x - b.x) < epsilon &&\n Math.abs(a.y - b.y) < epsilon &&\n Math.abs(a.z - b.z) < epsilon\n )\n }\n}\n\n/**\n * A 3D vector with `x`, `y`, and `z` components.\n *\n * Used throughout the plugin API for positions, directions, displacements,\n * and Euler rotation angles. Equivalent to `BABYLON.Vector3`.\n */\nexport const PVec3 = z.object({\n x: z.number(),\n y: z.number(),\n z: z.number(),\n})\n\nexport type PVec3 = z.infer<typeof PVec3>\n","import * as z from \"zod\"\nimport type { PVec3 } from \"./vec3\"\n\n/**\n * Quaternion operations for 3D rotations.\n *\n * Quaternions avoid gimbal lock and provide smooth interpolation\n * compared to Euler angles. All methods are **pure** — they return\n * new {@linkcode PQuat} values without mutating the inputs.\n *\n * Accessed via `snaptrude.core.math.quat`.\n */\nexport abstract class PluginQuatApi {\n constructor() {}\n\n /**\n * Create a new quaternion from raw components.\n *\n * For most use cases prefer {@linkcode PluginQuatApi.fromAxisAngle}\n * or {@linkcode PluginQuatApi.fromEuler} instead.\n *\n * @param x - The X component\n * @param y - The Y component\n * @param z - The Z component\n * @param w - The W (scalar) component\n * @returns A new {@linkcode PQuat}\n */\n new(x: number, y: number, z: number, w: number): PQuat {\n return { x, y, z, w }\n }\n\n /**\n * Create an identity quaternion representing no rotation.\n *\n * @returns `{ x: 0, y: 0, z: 0, w: 1 }`\n */\n identity(): PQuat {\n return { x: 0, y: 0, z: 0, w: 1 }\n }\n\n /**\n * Create a quaternion from an axis and an angle.\n *\n * @param axis - The rotation axis as a {@linkcode PVec3} (will be normalized internally)\n * @param angle - The rotation angle in **radians**\n * @returns A new unit {@linkcode PQuat}, or identity if {@linkcode axis} has zero length\n *\n * # Example\n * ```ts\n * const { vec3, quat } = snaptrude.core.math\n * // 90° rotation around the Y axis\n * const rot = quat.fromAxisAngle(vec3.new(0, 1, 0), Math.PI / 2)\n * ```\n */\n fromAxisAngle(axis: PVec3, angle: number): PQuat {\n const halfAngle = angle / 2\n const s = Math.sin(halfAngle)\n const len = Math.sqrt(axis.x * axis.x + axis.y * axis.y + axis.z * axis.z)\n if (len === 0) return { x: 0, y: 0, z: 0, w: 1 }\n return {\n x: (axis.x / len) * s,\n y: (axis.y / len) * s,\n z: (axis.z / len) * s,\n w: Math.cos(halfAngle),\n }\n }\n\n /**\n * Create a quaternion from Euler angles in **XYZ** rotation order.\n *\n * @param x - Rotation around X axis in **radians**\n * @param y - Rotation around Y axis in **radians**\n * @param z - Rotation around Z axis in **radians**\n * @returns A new {@linkcode PQuat}\n */\n fromEuler(x: number, y: number, z: number): PQuat {\n const cx = Math.cos(x / 2)\n const sx = Math.sin(x / 2)\n const cy = Math.cos(y / 2)\n const sy = Math.sin(y / 2)\n const cz = Math.cos(z / 2)\n const sz = Math.sin(z / 2)\n return {\n x: sx * cy * cz + cx * sy * sz,\n y: cx * sy * cz - sx * cy * sz,\n z: cx * cy * sz + sx * sy * cz,\n w: cx * cy * cz - sx * sy * sz,\n }\n }\n\n /**\n * Multiply two quaternions, combining their rotations.\n *\n * Quaternion multiplication is **not commutative**: `a * b ≠ b * a`.\n * The result applies rotation {@linkcode b} first, then {@linkcode a}.\n *\n * @param a - First quaternion (applied second)\n * @param b - Second quaternion (applied first)\n * @returns A new {@linkcode PQuat} representing the combined rotation\n */\n multiply(a: PQuat, b: PQuat): PQuat {\n return {\n x: a.w * b.x + a.x * b.w + a.y * b.z - a.z * b.y,\n y: a.w * b.y - a.x * b.z + a.y * b.w + a.z * b.x,\n z: a.w * b.z + a.x * b.y - a.y * b.x + a.z * b.w,\n w: a.w * b.w - a.x * b.x - a.y * b.y - a.z * b.z,\n }\n }\n\n /**\n * Compute the conjugate of a quaternion.\n *\n * For unit quaternions the conjugate equals the inverse.\n *\n * @param q - The quaternion\n * @returns A new {@linkcode PQuat} with negated vector part `(-x, -y, -z, w)`\n */\n conjugate(q: PQuat): PQuat {\n return { x: -q.x, y: -q.y, z: -q.z, w: q.w }\n }\n\n /**\n * Compute the length (magnitude) of a quaternion.\n *\n * @param q - The quaternion\n * @returns The magnitude `√(x² + y² + z² + w²)`\n */\n length(q: PQuat): number {\n return Math.sqrt(q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w)\n }\n\n /**\n * Normalize a quaternion to unit length.\n *\n * @param q - The quaternion to normalize\n * @returns A new unit-length {@linkcode PQuat}, or identity if the input has zero length\n */\n normalize(q: PQuat): PQuat {\n const len = this.length(q)\n if (len === 0) return { x: 0, y: 0, z: 0, w: 1 }\n return { x: q.x / len, y: q.y / len, z: q.z / len, w: q.w / len }\n }\n\n /**\n * Compute the inverse of a quaternion.\n *\n * The inverse satisfies `q * inverse(q) = identity`.\n *\n * @param q - The quaternion to invert\n * @returns A new {@linkcode PQuat} that is the multiplicative inverse,\n * or identity if the input has zero length\n */\n inverse(q: PQuat): PQuat {\n const lenSq = q.x * q.x + q.y * q.y + q.z * q.z + q.w * q.w\n if (lenSq === 0) return { x: 0, y: 0, z: 0, w: 1 }\n return { x: -q.x / lenSq, y: -q.y / lenSq, z: -q.z / lenSq, w: q.w / lenSq }\n }\n\n /**\n * Rotate a 3D vector by a quaternion.\n *\n * Computes `q * v * conjugate(q)` using the Hamilton product.\n *\n * @param q - The rotation quaternion (should be unit-length)\n * @param v - The vector to rotate as a {@linkcode PVec3}\n * @returns A new rotated {@linkcode PVec3}\n *\n * # Example\n * ```ts\n * const { vec3, quat } = snaptrude.core.math\n * const rot = quat.fromAxisAngle(vec3.new(0, 1, 0), Math.PI / 2)\n * const rotated = quat.rotateVec3(rot, vec3.new(1, 0, 0))\n * // ≈ { x: 0, y: 0, z: -1 }\n * ```\n */\n rotateVec3(q: PQuat, v: PVec3): PVec3 {\n const vq: PQuat = { x: v.x, y: v.y, z: v.z, w: 0 }\n const conj = this.conjugate(q)\n const result = this.multiply(this.multiply(q, vq), conj)\n return { x: result.x, y: result.y, z: result.z }\n }\n\n /**\n * Convert a quaternion to axis-angle representation.\n *\n * @param q - The quaternion to convert\n * @returns An object with:\n * - `axis` — The rotation axis as a unit {@linkcode PVec3}\n * (defaults to `(1, 0, 0)` when angle is zero)\n * - `angle` — The rotation angle in **radians**\n */\n toAxisAngle(q: PQuat): { axis: PVec3; angle: number } {\n const nq = this.normalize(q)\n const angle = 2 * Math.acos(Math.min(1, Math.max(-1, nq.w)))\n const s = Math.sin(angle / 2)\n if (s < 1e-6) {\n return { axis: { x: 1, y: 0, z: 0 }, angle: 0 }\n }\n return {\n axis: { x: nq.x / s, y: nq.y / s, z: nq.z / s },\n angle,\n }\n }\n\n /**\n * Spherical linear interpolation between two quaternions.\n *\n * Produces smooth constant-speed rotation between {@linkcode a} and {@linkcode b}.\n *\n * @param a - Start quaternion (returned when `t = 0`)\n * @param b - End quaternion (returned when `t = 1`)\n * @param t - Interpolation factor, typically in `[0, 1]`\n * @returns A new interpolated {@linkcode PQuat}\n */\n slerp(a: PQuat, b: PQuat, t: number): PQuat {\n let cosHalf = a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w\n let bx = b.x, by = b.y, bz = b.z, bw = b.w\n if (cosHalf < 0) {\n cosHalf = -cosHalf\n bx = -bx; by = -by; bz = -bz; bw = -bw\n }\n if (cosHalf >= 1.0) {\n return { x: a.x, y: a.y, z: a.z, w: a.w }\n }\n const halfAngle = Math.acos(cosHalf)\n const sinHalf = Math.sin(halfAngle)\n const ratioA = Math.sin((1 - t) * halfAngle) / sinHalf\n const ratioB = Math.sin(t * halfAngle) / sinHalf\n return {\n x: a.x * ratioA + bx * ratioB,\n y: a.y * ratioA + by * ratioB,\n z: a.z * ratioA + bz * ratioB,\n w: a.w * ratioA + bw * ratioB,\n }\n }\n\n /**\n * Compute the dot product of two quaternions.\n *\n * A value close to `1` or `-1` indicates similar orientations;\n * a value close to `0` indicates maximally different orientations.\n *\n * @param a - First quaternion\n * @param b - Second quaternion\n * @returns The scalar dot product\n */\n dot(a: PQuat, b: PQuat): number {\n return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w\n }\n\n /**\n * Check if two quaternions are exactly equal (strict equality per component).\n *\n * For floating-point comparisons, prefer {@linkcode PluginQuatApi.equalsApprox}.\n *\n * @param a - First quaternion\n * @param b - Second quaternion\n * @returns `true` if all components match exactly\n */\n equals(a: PQuat, b: PQuat): boolean {\n return a.x === b.x && a.y === b.y && a.z === b.z && a.w === b.w\n }\n\n /**\n * Check if two quaternions are approximately equal within a tolerance.\n *\n * @param a - First quaternion\n * @param b - Second quaternion\n * @param epsilon - Maximum allowed difference per component (default `1e-6`)\n * @returns `true` if `|a[i] - b[i]| < epsilon` for all components\n */\n equalsApprox(a: PQuat, b: PQuat, epsilon: number = 1e-6): boolean {\n return (\n Math.abs(a.x - b.x) < epsilon &&\n Math.abs(a.y - b.y) < epsilon &&\n Math.abs(a.z - b.z) < epsilon &&\n Math.abs(a.w - b.w) < epsilon\n )\n }\n}\n\n/**\n * A quaternion with `x`, `y`, `z`, and `w` components.\n *\n * Used for representing 3D rotations without gimbal lock.\n * Equivalent to `BABYLON.Quaternion`.\n */\nexport const PQuat = z.object({\n x: z.number(),\n y: z.number(),\n z: z.number(),\n w: z.number(),\n})\n\nexport type PQuat = z.infer<typeof PQuat>\n","import { PluginVec3Api } from \"./vec3\"\nimport { PluginQuatApi } from \"./quat\"\n\n/**\n * Math primitives for 3D vector and quaternion operations.\n *\n * - {@linkcode PluginMathApi.vec3} — 3D vector creation and arithmetic\n * - {@linkcode PluginMathApi.quat} — Quaternion creation and rotation operations\n */\nexport abstract class PluginMathApi {\n /** 3D vector operations. See {@linkcode PluginVec3Api}. */\n public abstract vec3: PluginVec3Api\n /** Quaternion operations. See {@linkcode PluginQuatApi}. */\n public abstract quat: PluginQuatApi\n\n constructor() {}\n}\n\nexport * from \"./vec3\"\nexport * from \"./quat\"\n","import * as z from \"zod\"\nimport { PVec3 } from \"../math/vec3\"\n\n/**\n * Line segment construction.\n *\n * A {@linkcode PLine} is the simplest curve primitive — a straight\n * segment between two 3D points. Lines can be wrapped as a\n * {@linkcode PCurve} and combined into a {@linkcode PProfile}.\n *\n * Accessed via `snaptrude.core.geom.line`.\n */\nexport abstract class PluginLineApi {\n constructor() {}\n\n /**\n * Create a new line segment between two points.\n *\n * @param startPoint - The start point as a {@linkcode PVec3}\n * @param endPoint - The end point as a {@linkcode PVec3}\n * @returns A new {@linkcode PLine}\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n * const { line } = snaptrude.core.geom\n *\n * const edge = line.new(vec3.new(0, 0, 0), vec3.new(5, 0, 0))\n * ```\n */\n new(startPoint: PVec3, endPoint: PVec3): PLine {\n return { curveType: \"Line\", startPoint, endPoint }\n }\n}\n\n/**\n * A line segment defined by a start and end point.\n *\n * Discriminated by `curveType: \"Line\"` within the {@linkcode PCurve} union.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curveType` | `\"Line\"` | Discriminator tag |\n * | `startPoint` | {@linkcode PVec3} | Start point of the segment |\n * | `endPoint` | {@linkcode PVec3} | End point of the segment |\n */\nexport const PLine = z.object({\n curveType: z.literal(\"Line\"),\n startPoint: PVec3,\n endPoint: PVec3,\n})\n\nexport type PLine = z.infer<typeof PLine>\n","import * as z from \"zod\"\nimport { PVec3 } from \"../math/vec3\"\n\n/**\n * Arc construction.\n *\n * A {@linkcode PArc} represents a circular arc in 3D space, defined by\n * start/end points, a centre, and a rotation axis. Arcs can be wrapped\n * as a {@linkcode PCurve} and combined into a {@linkcode PProfile}.\n *\n * Accessed via `snaptrude.core.geom.arc`.\n */\nexport abstract class PluginArcApi {\n constructor() {}\n\n /**\n * Create a new arc from start, end, centre, and axis.\n *\n * The arc sweeps from {@linkcode startPoint} to {@linkcode endPoint}\n * along the circle centred at {@linkcode centrePoint}, in the\n * direction determined by the right-hand rule around {@linkcode axis}.\n *\n * @param startPoint - The start point as a {@linkcode PVec3}\n * @param endPoint - The end point as a {@linkcode PVec3}\n * @param centrePoint - The centre of the arc's circle as a {@linkcode PVec3}\n * @param axis - The arc's rotation axis as a {@linkcode PVec3}\n * (perpendicular to the arc's plane)\n * @returns A new {@linkcode PArc}\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n * const { arc } = snaptrude.core.geom\n *\n * // Quarter-circle arc on the XZ plane\n * const a = arc.new(\n * vec3.new(1, 0, 0), // start\n * vec3.new(0, 0, 1), // end\n * vec3.new(0, 0, 0), // centre\n * vec3.new(0, 1, 0), // Y-up axis\n * )\n * ```\n */\n new(startPoint: PVec3, endPoint: PVec3, centrePoint: PVec3, axis: PVec3): PArc {\n return { curveType: \"Arc\", startPoint, endPoint, centrePoint, axis }\n }\n}\n\n/**\n * A circular arc defined by start, end, centre, and axis.\n *\n * Discriminated by `curveType: \"Arc\"` within the {@linkcode PCurve} union.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curveType` | `\"Arc\"` | Discriminator tag |\n * | `startPoint` | {@linkcode PVec3} | Start point of the arc |\n * | `endPoint` | {@linkcode PVec3} | End point of the arc |\n * | `centrePoint` | {@linkcode PVec3} | Centre of the arc's circle |\n * | `axis` | {@linkcode PVec3} | Rotation axis (normal to the arc's plane) |\n */\nexport const PArc = z.object({\n curveType: z.literal(\"Arc\"),\n startPoint: PVec3,\n endPoint: PVec3,\n centrePoint: PVec3,\n axis: PVec3,\n})\n\nexport type PArc = z.infer<typeof PArc>\n","import * as z from \"zod\"\nimport { PLine } from \"./line\"\nimport { PArc } from \"./arc\"\n\n/**\n * Unified curve wrapper — either a {@linkcode PLine} or a {@linkcode PArc}.\n *\n * Use this to build heterogeneous curve lists (mixing lines and arcs)\n * when constructing a {@linkcode PProfile}.\n *\n * Accessed via `snaptrude.core.geom.curve`.\n */\nexport abstract class PluginCurveApi {\n constructor() {}\n\n /**\n * Wrap a {@linkcode PLine} or {@linkcode PArc} as a {@linkcode PCurve}.\n *\n * This is an identity operation — it simply returns the input unchanged.\n * It exists for type-level clarity when building mixed curve lists.\n *\n * @param curve - A {@linkcode PLine} or {@linkcode PArc} to wrap\n * @returns The same value typed as {@linkcode PCurve}\n */\n new(curve: PLine | PArc): PCurve {\n return curve\n }\n}\n\n/**\n * A discriminated union of {@linkcode PLine} and {@linkcode PArc}.\n *\n * Discriminated on the `curveType` field:\n * - `\"Line\"` → {@linkcode PLine}\n * - `\"Arc\"` → {@linkcode PArc}\n *\n * Use `curve.curveType` to narrow the type in a switch or if-statement.\n */\nexport const PCurve = z.discriminatedUnion(\"curveType\", [PLine, PArc])\n\nexport type PCurve = z.infer<typeof PCurve>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { PVec3 } from \"../math/vec3\"\nimport { PCurve } from \"./curve\"\n\n/**\n * Profile construction — a closed loop of {@linkcode PCurve}s.\n *\n * Profiles are the primary 2D shape primitive used for creating\n * extruded entities like spaces. Build profiles either from an\n * explicit list of curves or from a list of points (auto-connected\n * with line segments).\n *\n * Accessed via `snaptrude.core.geom.profile`.\n */\nexport abstract class PluginProfileApi {\n constructor() {}\n\n /**\n * Create a profile from an ordered list of curves.\n *\n * The curves should form a closed loop — the end point of each curve\n * should coincide with the start point of the next.\n *\n * @param curves - An ordered array of {@linkcode PCurve}s forming a closed loop\n * @returns A new {@linkcode PProfile}\n */\n new(curves: PCurve[]): PProfile {\n return { curves }\n }\n\n /**\n * Create a profile by connecting a list of points with line segments.\n *\n * The points are connected in order, with the last point automatically\n * connected back to the first to close the loop.\n *\n * This is a **host API call** — it returns a `Promise`.\n *\n * @param args - An object containing:\n * - {@linkcode PluginProfileFromLinePointsArgs.points args.points} — An ordered\n * array of {@linkcode PVec3} forming the profile vertices\n * @returns A {@linkcode PProfile} with line-segment curves connecting the points\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n *\n * // Create an L-shaped profile\n * const profile = await snaptrude.core.geom.profile.fromLinePoints({\n * points: [\n * vec3.new(0, 0, 0),\n * vec3.new(10, 0, 0),\n * vec3.new(10, 0, 5),\n * vec3.new(5, 0, 5),\n * vec3.new(5, 0, 10),\n * vec3.new(0, 0, 10),\n * ],\n * })\n * ```\n */\n public abstract fromLinePoints(\n args: PluginProfileFromLinePointsArgs\n ): PluginApiReturn<PProfile>\n}\n\n/**\n * Arguments for {@linkcode PluginProfileApi.fromLinePoints}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `points` | {@linkcode PVec3}`[]` | Ordered vertices of the profile |\n */\nexport const PluginProfileFromLinePointsArgs = z.object({\n points: z.array(PVec3),\n})\n\nexport type PluginProfileFromLinePointsArgs = z.infer<typeof PluginProfileFromLinePointsArgs>\n\n/**\n * A closed profile composed of an ordered list of curves.\n *\n * Profiles are used as input to entity creation methods like\n * {@linkcode PluginSpaceApi.createFromProfile}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curves` | {@linkcode PCurve}`[]` | Ordered curves forming a closed loop |\n */\nexport const PProfile = z.object({\n curves: z.array(PCurve),\n})\n\nexport type PProfile = z.infer<typeof PProfile>\n","import { PluginLineApi } from \"./line\"\nimport { PluginArcApi } from \"./arc\"\nimport { PluginCurveApi } from \"./curve\"\nimport { PluginProfileApi } from \"./profile\"\n\n/**\n * Geometry primitives for constructing 2D/3D shapes.\n *\n * Build geometry bottom-up: points ({@linkcode PVec3}) → lines/arcs → curves → profiles.\n * Profiles can then be used with entity creation methods like\n * {@linkcode PluginSpaceApi.createFromProfile}.\n *\n * - {@linkcode PluginGeomApi.line} — Line segment construction\n * - {@linkcode PluginGeomApi.arc} — Arc construction\n * - {@linkcode PluginGeomApi.curve} — Unified curve wrapper (line or arc)\n * - {@linkcode PluginGeomApi.profile} — Closed loop of curves\n */\nexport abstract class PluginGeomApi {\n /** Line segment construction. See {@linkcode PluginLineApi}. */\n public abstract line: PluginLineApi\n /** Arc construction. See {@linkcode PluginArcApi}. */\n public abstract arc: PluginArcApi\n /** Unified curve wrapper. See {@linkcode PluginCurveApi}. */\n public abstract curve: PluginCurveApi\n /** Closed profile (loop of curves). See {@linkcode PluginProfileApi}. */\n public abstract profile: PluginProfileApi\n\n constructor() {}\n}\n\nexport * from \"./line\"\nexport * from \"./arc\"\nexport * from \"./curve\"\nexport * from \"./profile\"\n","import { PluginMathApi } from \"./math\"\nimport { PluginGeomApi } from \"./geom\"\n\n/**\n * Core primitives used across the plugin API.\n *\n * - {@linkcode PluginCoreApi.math} — Vector and quaternion operations\n * - {@linkcode PluginCoreApi.geom} — Geometry primitives (lines, arcs, curves, profiles)\n */\nexport abstract class PluginCoreApi {\n /** Vector and quaternion math utilities. See {@linkcode PluginMathApi}. */\n public abstract math: PluginMathApi\n /** Geometry primitives and constructors. See {@linkcode PluginGeomApi}. */\n public abstract geom: PluginGeomApi\n\n constructor() {}\n}\n\nexport * from \"./math\"\nexport * from \"./geom\"\n","import * as z from \"zod\"\nimport type { PluginApiReturn } from \"../../types\"\n\nconst JsonPrimitive = z.union([z.string(), z.number(), z.boolean(), z.null()])\ntype JsonValue =\n | z.infer<typeof JsonPrimitive>\n | JsonValue[]\n | { [key: string]: JsonValue }\nconst JsonValue: z.ZodType<JsonValue> = z.lazy(() =>\n z.union([JsonPrimitive, z.array(JsonValue), z.record(z.string(), JsonValue)]),\n)\n\nexport const PluginAIInspirationRunMode = z.enum([\"blocking\", \"job\"])\nexport type PluginAIInspirationRunMode = z.infer<\n typeof PluginAIInspirationRunMode\n>\n\nexport const PluginAIInspirationOutputKind = z.enum([\n \"source\",\n \"image\",\n \"video\",\n])\nexport type PluginAIInspirationOutputKind = z.infer<\n typeof PluginAIInspirationOutputKind\n>\n\nexport const PluginAIInspirationModelOutput = z.enum([\"image\", \"video\"])\nexport type PluginAIInspirationModelOutput = z.infer<\n typeof PluginAIInspirationModelOutput\n>\n\nexport const PluginAIInspirationRuntimeProvider = z.enum([\"gpt\", \"fal\"])\nexport type PluginAIInspirationRuntimeProvider = z.infer<\n typeof PluginAIInspirationRuntimeProvider\n>\n\nexport const PluginAIInspirationPromptStrategy = z.enum([\n \"gpt-image\",\n \"fal-image\",\n \"fal-video\",\n])\nexport type PluginAIInspirationPromptStrategy = z.infer<\n typeof PluginAIInspirationPromptStrategy\n>\n\nexport const PluginAIInspirationShapeKind = z.enum([\"image\", \"view\", \"video\"])\nexport type PluginAIInspirationShapeKind = z.infer<\n typeof PluginAIInspirationShapeKind\n>\n\nexport const PluginAIInspirationVideoMode = z.enum([\n \"animate\",\n \"references\",\n \"keyframes\",\n])\nexport type PluginAIInspirationVideoMode = z.infer<\n typeof PluginAIInspirationVideoMode\n>\n\nexport const PluginAIInspirationVideoMotion = z.enum([\n \"auto\",\n \"slow-dolly\",\n \"subtle-orbit\",\n \"reveal\",\n])\nexport type PluginAIInspirationVideoMotion = z.infer<\n typeof PluginAIInspirationVideoMotion\n>\n\nexport const PluginAIInspirationVideoDuration = z.enum([\"4s\", \"6s\", \"8s\"])\nexport type PluginAIInspirationVideoDuration = z.infer<\n typeof PluginAIInspirationVideoDuration\n>\n\nexport const PluginAIInspirationJobStatus = z.enum([\n \"queued\",\n \"running\",\n \"completed\",\n \"failed\",\n \"cancelled\",\n])\nexport type PluginAIInspirationJobStatus = z.infer<\n typeof PluginAIInspirationJobStatus\n>\n\nexport const PluginAIInspirationWorkflowRunState = z.enum([\n \"current\",\n \"stale\",\n \"running\",\n \"failed\",\n \"superseded\",\n])\nexport type PluginAIInspirationWorkflowRunState = z.infer<\n typeof PluginAIInspirationWorkflowRunState\n>\n\nexport const PluginAIInspirationRegionHint = z.object({\n x: z.number().finite(),\n y: z.number().finite(),\n w: z.number().finite().positive(),\n h: z.number().finite().positive(),\n})\nexport type PluginAIInspirationRegionHint = z.infer<\n typeof PluginAIInspirationRegionHint\n>\n\nexport const PluginAIInspirationPoint = z.object({\n x: z.number().finite(),\n y: z.number().finite(),\n})\nexport type PluginAIInspirationPoint = z.infer<typeof PluginAIInspirationPoint>\n\nexport const PluginAIInspirationTextAnnotation = z.object({\n text: z.string().min(1),\n x: z.number().finite().optional(),\n y: z.number().finite().optional(),\n})\nexport type PluginAIInspirationTextAnnotation = z.infer<\n typeof PluginAIInspirationTextAnnotation\n>\n\nexport const PluginAIInspirationSketchGuidance = z.object({\n visualShapeIds: z.array(z.string()).optional(),\n textAnnotations: z.array(PluginAIInspirationTextAnnotation).optional(),\n})\nexport type PluginAIInspirationSketchGuidance = z.infer<\n typeof PluginAIInspirationSketchGuidance\n>\n\nexport const PluginAIInspirationSiteOptions = z.object({\n includeSatellite: z.boolean().optional(),\n includeStreetView: z.boolean().optional(),\n includeAerial: z.boolean().optional(),\n aerialBearing: z.number().finite().optional(),\n aerialPitch: z.number().finite().optional(),\n selectedDiagramIds: z.array(z.string()).optional(),\n location: z\n .object({\n lat: z.number().finite(),\n lng: z.number().finite(),\n })\n .optional(),\n})\nexport type PluginAIInspirationSiteOptions = z.infer<\n typeof PluginAIInspirationSiteOptions\n>\n\nexport const PluginAIInspirationAppliedPreset = z.object({\n source: z.enum([\"curated\", \"user\"]),\n presetId: z.string().min(1),\n name: z.string().min(1),\n savedPresetKind: z.enum([\"prompt\", \"style\"]).optional(),\n stylePrompt: z.string().optional(),\n modelId: z.string().optional(),\n referenceImages: z\n .array(\n z.object({\n url: z.string().min(1),\n label: z.string().optional(),\n weight: z.number().finite().optional(),\n }),\n )\n .optional(),\n siteDefaults: z\n .object({\n includeSatellite: z.boolean().optional(),\n includeStreetView: z.boolean().optional(),\n includeAerial: z.boolean().optional(),\n })\n .optional(),\n})\nexport type PluginAIInspirationAppliedPreset = z.infer<\n typeof PluginAIInspirationAppliedPreset\n>\n\nexport const PluginAIInspirationVideoOptions = z.object({\n mode: PluginAIInspirationVideoMode.optional(),\n endFrameShapeId: z.string().optional(),\n motion: PluginAIInspirationVideoMotion.optional(),\n duration: PluginAIInspirationVideoDuration.optional(),\n})\nexport type PluginAIInspirationVideoOptions = z.infer<\n typeof PluginAIInspirationVideoOptions\n>\n\nexport const PluginAIInspirationModel = z.object({\n id: z.string(),\n label: z.string(),\n supportsMultiImage: z.boolean(),\n output: PluginAIInspirationModelOutput,\n isDefault: z.boolean().optional(),\n})\nexport type PluginAIInspirationModel = z.infer<typeof PluginAIInspirationModel>\n\nexport const PluginAIInspirationModelCapability = z.object({\n id: z.string(),\n output: PluginAIInspirationModelOutput,\n provider: PluginAIInspirationRuntimeProvider,\n supportsRegionEdit: z.boolean(),\n supportsReferenceImages: z.boolean(),\n supportsStylePresets: z.boolean(),\n supportsSiteContext: z.boolean(),\n supportsSketchGuidance: z.boolean(),\n supportsKeyframes: z.boolean(),\n maxExtraImages: z.number().int().nonnegative(),\n promptStrategy: PluginAIInspirationPromptStrategy,\n})\nexport type PluginAIInspirationModelCapability = z.infer<\n typeof PluginAIInspirationModelCapability\n>\n\nexport const PluginAIInspirationListModelsResult = z.object({\n defaultModelId: z.string(),\n models: z.array(PluginAIInspirationModel),\n})\nexport type PluginAIInspirationListModelsResult = z.infer<\n typeof PluginAIInspirationListModelsResult\n>\n\nexport const PluginAIInspirationGetModelCapabilitiesArgs = z.object({\n modelId: z.string().min(1),\n})\nexport type PluginAIInspirationGetModelCapabilitiesArgs = z.infer<\n typeof PluginAIInspirationGetModelCapabilitiesArgs\n>\n\nexport const PluginAIInspirationGetModelCapabilitiesResult = z.object({\n capability: PluginAIInspirationModelCapability,\n})\nexport type PluginAIInspirationGetModelCapabilitiesResult = z.infer<\n typeof PluginAIInspirationGetModelCapabilitiesResult\n>\n\nexport const PluginAIInspirationShapeRef = z.object({\n shapeId: z.string(),\n assetId: z.string().optional(),\n kind: PluginAIInspirationShapeKind,\n name: z.string().optional(),\n width: z.number().finite().optional(),\n height: z.number().finite().optional(),\n outputType: PluginAIInspirationOutputKind.optional(),\n sourceUrl: z.string().optional(),\n})\nexport type PluginAIInspirationShapeRef = z.infer<\n typeof PluginAIInspirationShapeRef\n>\n\nexport const PluginAIInspirationListSourcesArgs = z.object({\n includeGenerated: z.boolean().optional(),\n includeSourceUrl: z.boolean().optional(),\n})\nexport type PluginAIInspirationListSourcesArgs = z.infer<\n typeof PluginAIInspirationListSourcesArgs\n>\n\nexport const PluginAIInspirationListSourcesResult = z.object({\n sources: z.array(PluginAIInspirationShapeRef),\n})\nexport type PluginAIInspirationListSourcesResult = z.infer<\n typeof PluginAIInspirationListSourcesResult\n>\n\nexport const PluginAIInspirationGetSelectionResult = z.object({\n selectedShapeIds: z.array(z.string()),\n sources: z.array(PluginAIInspirationShapeRef),\n})\nexport type PluginAIInspirationGetSelectionResult = z.infer<\n typeof PluginAIInspirationGetSelectionResult\n>\n\nexport const PluginAIInspirationPresetReferenceImage = z.object({\n url: z.string(),\n label: z.string().optional(),\n weight: z.number().finite().optional(),\n})\nexport type PluginAIInspirationPresetReferenceImage = z.infer<\n typeof PluginAIInspirationPresetReferenceImage\n>\n\nexport const PluginAIInspirationPreset = z.object({\n id: z.string(),\n name: z.string(),\n source: z.enum([\"curated\", \"user\"]),\n modelId: z.string(),\n categoryId: z.string().optional(),\n categoryLabel: z.string().optional(),\n description: z.string().optional(),\n previewImageUrl: z.string().optional(),\n prompt: z.string().optional(),\n stylePrompt: z.string().optional(),\n tags: z.array(z.string()).optional(),\n referenceImages: z.array(PluginAIInspirationPresetReferenceImage).optional(),\n siteDefaults: PluginAIInspirationAppliedPreset.shape.siteDefaults.optional(),\n})\nexport type PluginAIInspirationPreset = z.infer<\n typeof PluginAIInspirationPreset\n>\n\nexport const PluginAIInspirationPresetCategory = z.object({\n id: z.string(),\n label: z.string(),\n description: z.string().optional(),\n})\nexport type PluginAIInspirationPresetCategory = z.infer<\n typeof PluginAIInspirationPresetCategory\n>\n\nexport const PluginAIInspirationGetPresetCatalogResult = z.object({\n categories: z.array(PluginAIInspirationPresetCategory),\n presets: z.array(PluginAIInspirationPreset),\n})\nexport type PluginAIInspirationGetPresetCatalogResult = z.infer<\n typeof PluginAIInspirationGetPresetCatalogResult\n>\n\nexport const PluginAIInspirationOutput = z.object({\n outputType: z.enum([\"image\", \"video\"]),\n shapeId: z.string(),\n assetId: z.string(),\n outputUrl: z.string().optional(),\n position: PluginAIInspirationPoint.optional(),\n})\nexport type PluginAIInspirationOutput = z.infer<\n typeof PluginAIInspirationOutput\n>\n\nexport const PluginAIInspirationDebugSummary = z.record(z.string(), JsonValue)\nexport type PluginAIInspirationDebugSummary = z.infer<\n typeof PluginAIInspirationDebugSummary\n>\n\nexport const PluginAIInspirationRunMetadata = z.object({\n geometryFidelity: z.string().optional(),\n debugSummary: PluginAIInspirationDebugSummary.optional(),\n streetViewComposite: z\n .object({\n used: z.boolean(),\n renderMode: z.enum([\"prompt_refs_default\", \"masked_composite_pilot\"]),\n backgroundLabel: z.string().optional(),\n })\n .optional(),\n})\nexport type PluginAIInspirationRunMetadata = z.infer<\n typeof PluginAIInspirationRunMetadata\n>\n\nexport const PluginAIInspirationGenerateArgs = z.object({\n sourceShapeId: z.string().min(1),\n prompt: z.string().min(1).max(8000),\n modelId: z.string().optional(),\n referenceShapeIds: z.array(z.string()).max(12).optional(),\n referenceStrength: z.enum([\"low\", \"medium\", \"high\"]).optional(),\n appliedPreset: PluginAIInspirationAppliedPreset.optional(),\n site: PluginAIInspirationSiteOptions.optional(),\n regionHint: PluginAIInspirationRegionHint.optional(),\n sketchGuidance: PluginAIInspirationSketchGuidance.optional(),\n video: PluginAIInspirationVideoOptions.optional(),\n runMode: PluginAIInspirationRunMode.optional(),\n})\nexport type PluginAIInspirationGenerateArgs = z.infer<\n typeof PluginAIInspirationGenerateArgs\n>\n\nexport const PluginAIInspirationRunResult = z.object({\n jobId: z.string().optional(),\n output: PluginAIInspirationOutput.optional(),\n outputs: z.array(PluginAIInspirationOutput).optional(),\n metadata: PluginAIInspirationRunMetadata.optional(),\n})\nexport type PluginAIInspirationRunResult = z.infer<\n typeof PluginAIInspirationRunResult\n>\n\nexport const PluginAIInspirationRefineArgs = z.object({\n sourceShapeId: z.string().min(1),\n upscaleFactor: z\n .union([z.literal(1.5), z.literal(2), z.literal(4)])\n .optional(),\n runMode: PluginAIInspirationRunMode.optional(),\n})\nexport type PluginAIInspirationRefineArgs = z.infer<\n typeof PluginAIInspirationRefineArgs\n>\n\nexport const PluginAIInspirationJobProgress = z.object({\n currentStep: z.number().int().nonnegative().optional(),\n totalSteps: z.number().int().nonnegative().optional(),\n message: z.string().optional(),\n})\nexport type PluginAIInspirationJobProgress = z.infer<\n typeof PluginAIInspirationJobProgress\n>\n\nexport const PluginAIInspirationJob = z.object({\n jobId: z.string(),\n status: PluginAIInspirationJobStatus,\n createdAt: z.number(),\n updatedAt: z.number(),\n completedAt: z.number().optional(),\n method: z.string(),\n progress: PluginAIInspirationJobProgress.optional(),\n result: PluginAIInspirationRunResult.optional(),\n error: z.string().optional(),\n})\nexport type PluginAIInspirationJob = z.infer<typeof PluginAIInspirationJob>\n\nexport const PluginAIInspirationJobArgs = z.object({\n jobId: z.string().min(1),\n})\nexport type PluginAIInspirationJobArgs = z.infer<\n typeof PluginAIInspirationJobArgs\n>\n\nexport const PluginAIInspirationGetJobResult = z.object({\n job: PluginAIInspirationJob,\n})\nexport type PluginAIInspirationGetJobResult = z.infer<\n typeof PluginAIInspirationGetJobResult\n>\n\nexport const PluginAIInspirationCancelJobResult = z.object({\n job: PluginAIInspirationJob,\n})\nexport type PluginAIInspirationCancelJobResult = z.infer<\n typeof PluginAIInspirationCancelJobResult\n>\n\nexport const PluginAIInspirationListJobsResult = z.object({\n jobs: z.array(PluginAIInspirationJob),\n})\nexport type PluginAIInspirationListJobsResult = z.infer<\n typeof PluginAIInspirationListJobsResult\n>\n\nexport const PluginAIInspirationWorkflowVideoConfig = z.object({\n mode: z.string().optional(),\n motion: z.string().optional(),\n duration: z.string().optional(),\n endFrameShapeId: z.string().optional(),\n})\nexport type PluginAIInspirationWorkflowVideoConfig = z.infer<\n typeof PluginAIInspirationWorkflowVideoConfig\n>\n\nexport const PluginAIInspirationGenerationInputSnapshot = z.object({\n version: z.literal(1),\n meta: z.record(z.string(), JsonValue),\n regionHint: PluginAIInspirationRegionHint.optional(),\n sketchGuidance: z.record(z.string(), JsonValue).optional(),\n sourceCameraHeading: z.number().finite().optional(),\n})\nexport type PluginAIInspirationGenerationInputSnapshot = z.infer<\n typeof PluginAIInspirationGenerationInputSnapshot\n>\n\nexport const PluginAIInspirationWorkflowOperation = z.object({\n type: z.enum([\"generate-image\", \"refine\", \"generate-video\"]),\n label: z.string(),\n prompt: z.string().optional(),\n modelId: z.string().optional(),\n presetId: z.string().optional(),\n presetName: z.string().optional(),\n refineFactor: z.number().finite().optional(),\n sourceRole: z.enum([\"primary\", \"end-frame\"]).optional(),\n video: PluginAIInspirationWorkflowVideoConfig.optional(),\n generationInput: PluginAIInspirationGenerationInputSnapshot.optional(),\n})\nexport type PluginAIInspirationWorkflowOperation = z.infer<\n typeof PluginAIInspirationWorkflowOperation\n>\n\nexport const PluginAIInspirationWorkflowNode = z.object({\n id: z.string(),\n shapeId: z.string(),\n assetId: z.string().optional(),\n kind: PluginAIInspirationOutputKind,\n state: z.string(),\n runState: PluginAIInspirationWorkflowRunState.optional(),\n staleReason: z.string().optional(),\n incomingEdgeIds: z.array(z.string()),\n outgoingEdgeIds: z.array(z.string()),\n createdAt: z.number(),\n updatedAt: z.number(),\n})\nexport type PluginAIInspirationWorkflowNode = z.infer<\n typeof PluginAIInspirationWorkflowNode\n>\n\nexport const PluginAIInspirationWorkflowEdge = z.object({\n id: z.string(),\n sourceNodeId: z.string(),\n targetNodeId: z.string(),\n arrowShapeId: z.string().optional(),\n operation: PluginAIInspirationWorkflowOperation,\n state: z.string(),\n runState: PluginAIInspirationWorkflowRunState.optional(),\n staleReason: z.string().optional(),\n supersededByEdgeId: z.string().optional(),\n createdAt: z.number(),\n updatedAt: z.number(),\n})\nexport type PluginAIInspirationWorkflowEdge = z.infer<\n typeof PluginAIInspirationWorkflowEdge\n>\n\nexport const PluginAIInspirationWorkflow = z.object({\n id: z.string(),\n rootNodeIds: z.array(z.string()),\n nodeIds: z.array(z.string()),\n edgeIds: z.array(z.string()),\n nodes: z.record(z.string(), PluginAIInspirationWorkflowNode),\n edges: z.record(z.string(), PluginAIInspirationWorkflowEdge),\n createdAt: z.number(),\n updatedAt: z.number(),\n})\nexport type PluginAIInspirationWorkflow = z.infer<\n typeof PluginAIInspirationWorkflow\n>\n\nexport const PluginAIInspirationGetWorkflowForShapeArgs = z.object({\n shapeId: z.string().min(1),\n})\nexport type PluginAIInspirationGetWorkflowForShapeArgs = z.infer<\n typeof PluginAIInspirationGetWorkflowForShapeArgs\n>\n\nexport const PluginAIInspirationGetWorkflowForShapeResult = z.object({\n workflow: PluginAIInspirationWorkflow.nullable(),\n node: PluginAIInspirationWorkflowNode.nullable(),\n})\nexport type PluginAIInspirationGetWorkflowForShapeResult = z.infer<\n typeof PluginAIInspirationGetWorkflowForShapeResult\n>\n\nexport const PluginAIInspirationRerunPlanResult = z.discriminatedUnion(\n \"status\",\n [\n z.object({\n status: z.literal(\"ready\"),\n workflowId: z.string(),\n sourceNode: PluginAIInspirationWorkflowNode,\n edgeIds: z.array(z.string()),\n edges: z.array(PluginAIInspirationWorkflowEdge),\n recipe: z.lazy(() => PluginAIInspirationRecipe),\n needsEndFrame: z.boolean(),\n defaultEndFrameShapeId: z.string().nullable(),\n }),\n z.object({\n status: z.literal(\"unavailable\"),\n reason: z.enum([\n \"not-in-workflow\",\n \"source-only\",\n \"running\",\n \"missing-input\",\n ]),\n }),\n ],\n)\nexport type PluginAIInspirationRerunPlanResult = z.infer<\n typeof PluginAIInspirationRerunPlanResult\n>\n\nexport const PluginAIInspirationRerunSelectedBranchArgs = z.object({\n shapeId: z.string().min(1),\n endFrameShapeId: z.string().optional(),\n runMode: PluginAIInspirationRunMode.optional(),\n})\nexport type PluginAIInspirationRerunSelectedBranchArgs = z.infer<\n typeof PluginAIInspirationRerunSelectedBranchArgs\n>\n\nexport const PluginAIInspirationRecipeSlot = z.object({\n id: z.string(),\n type: z.enum([\"source-image\", \"end-frame\"]),\n label: z.string(),\n required: z.boolean(),\n})\nexport type PluginAIInspirationRecipeSlot = z.infer<\n typeof PluginAIInspirationRecipeSlot\n>\n\nexport const PluginAIInspirationRecipeStep = z.object({\n id: z.string(),\n operation: PluginAIInspirationWorkflowOperation,\n outputKind: z.enum([\"image\", \"video\"]),\n})\nexport type PluginAIInspirationRecipeStep = z.infer<\n typeof PluginAIInspirationRecipeStep\n>\n\nexport const PluginAIInspirationRecipeDraft = z.object({\n name: z.string(),\n summary: z.string(),\n slots: z.array(PluginAIInspirationRecipeSlot),\n steps: z.array(PluginAIInspirationRecipeStep).min(1).max(20),\n outputKind: z.enum([\"image\", \"video\"]),\n thumbnailUrl: z.string().optional(),\n})\nexport type PluginAIInspirationRecipeDraft = z.infer<\n typeof PluginAIInspirationRecipeDraft\n>\n\nexport const PluginAIInspirationRecipe: z.ZodType<\n PluginAIInspirationRecipeDraft & {\n version: 1\n id: string\n fingerprint?: string\n createdAt: number\n updatedAt: number\n }\n> = PluginAIInspirationRecipeDraft.extend({\n version: z.literal(1),\n id: z.string(),\n fingerprint: z.string().optional(),\n createdAt: z.number(),\n updatedAt: z.number(),\n})\nexport type PluginAIInspirationRecipe = z.infer<\n typeof PluginAIInspirationRecipe\n>\n\nexport const PluginAIInspirationExtractionResult = z.discriminatedUnion(\n \"status\",\n [\n z.object({\n status: z.literal(\"ready\"),\n draft: PluginAIInspirationRecipeDraft,\n }),\n z.object({\n status: z.literal(\"unavailable\"),\n reason: z.enum([\n \"not-in-workflow\",\n \"source-only\",\n \"missing-workflow\",\n \"missing-node\",\n \"missing-input\",\n \"invalid-workflow\",\n ]),\n }),\n ],\n)\nexport type PluginAIInspirationExtractionResult = z.infer<\n typeof PluginAIInspirationExtractionResult\n>\n\nexport const PluginAIInspirationListRecipesResult = z.object({\n recipes: z.array(PluginAIInspirationRecipe),\n})\nexport type PluginAIInspirationListRecipesResult = z.infer<\n typeof PluginAIInspirationListRecipesResult\n>\n\nexport const PluginAIInspirationSaveRecipeArgs = z.object({\n draft: PluginAIInspirationRecipeDraft,\n name: z.string().min(1),\n})\nexport type PluginAIInspirationSaveRecipeArgs = z.infer<\n typeof PluginAIInspirationSaveRecipeArgs\n>\n\nexport const PluginAIInspirationSaveRecipeResult = z.discriminatedUnion(\n \"status\",\n [\n z.object({ status: z.literal(\"saved\"), recipe: PluginAIInspirationRecipe }),\n z.object({\n status: z.literal(\"duplicate\"),\n recipe: PluginAIInspirationRecipe,\n }),\n z.object({ status: z.literal(\"invalid-name\"), recipe: z.null() }),\n z.object({ status: z.literal(\"failed\"), recipe: z.null() }),\n ],\n)\nexport type PluginAIInspirationSaveRecipeResult = z.infer<\n typeof PluginAIInspirationSaveRecipeResult\n>\n\nexport const PluginAIInspirationDeleteRecipeArgs = z.object({\n recipeId: z.string().min(1),\n})\nexport type PluginAIInspirationDeleteRecipeArgs = z.infer<\n typeof PluginAIInspirationDeleteRecipeArgs\n>\n\nexport const PluginAIInspirationDeleteRecipeResult = z.object({\n deleted: z.boolean(),\n})\nexport type PluginAIInspirationDeleteRecipeResult = z.infer<\n typeof PluginAIInspirationDeleteRecipeResult\n>\n\nexport const PluginAIInspirationExtractRecipeFromShapeArgs = z.object({\n shapeId: z.string().min(1),\n})\nexport type PluginAIInspirationExtractRecipeFromShapeArgs = z.infer<\n typeof PluginAIInspirationExtractRecipeFromShapeArgs\n>\n\nexport const PluginAIInspirationRunRecipeArgs = z.object({\n recipeId: z.string().optional(),\n recipe: PluginAIInspirationRecipe.optional(),\n slotShapeIds: z.record(z.string(), z.string()),\n runMode: PluginAIInspirationRunMode.optional(),\n})\nexport type PluginAIInspirationRunRecipeArgs = z.infer<\n typeof PluginAIInspirationRunRecipeArgs\n>\n\n/**\n * Present-mode AI Inspiration APIs.\n *\n * These APIs operate on Present canvas shape IDs and inherit the current user's\n * AI quota. They create outputs on the Present canvas; pure backend generation\n * without canvas output is intentionally out of scope.\n *\n * Accessed via `snaptrude.documentation.aiInspiration`.\n */\nexport abstract class PluginDocumentationAIInspirationApi {\n constructor() {}\n\n /**\n * List AI Inspiration models that can be used for generation.\n *\n * @returns The default model ID and available model descriptors.\n */\n public abstract listModels(): PluginApiReturn<PluginAIInspirationListModelsResult>\n\n /**\n * Get capability flags for a model.\n *\n * @param args - Object containing `modelId`.\n * @returns Capability flags such as reference, site-context, region, and keyframe support.\n */\n public abstract getModelCapabilities(\n args: PluginAIInspirationGetModelCapabilitiesArgs,\n ): PluginApiReturn<PluginAIInspirationGetModelCapabilitiesResult>\n\n /**\n * List image/view/video sources on the current Present page.\n *\n * @param args - Optional filters. Set `includeGenerated` to include AI outputs.\n * @returns Serializable shape references using Present canvas shape IDs.\n */\n public abstract listSources(\n args: PluginAIInspirationListSourcesArgs,\n ): PluginApiReturn<PluginAIInspirationListSourcesResult>\n\n /**\n * Get selected Present canvas shapes that AI Inspiration can use.\n *\n * @returns Selected shape IDs and resolved source references.\n */\n public abstract getSelection(): PluginApiReturn<PluginAIInspirationGetSelectionResult>\n\n /**\n * Get the curated AI Inspiration preset catalog.\n *\n * @returns Preset categories and presets.\n */\n public abstract getPresetCatalog(): PluginApiReturn<PluginAIInspirationGetPresetCatalogResult>\n\n /**\n * Generate an image or video from a Present canvas source.\n *\n * @param args - Generation options including source, prompt, model, references, site context,\n * region guidance, sketch guidance, and video options.\n * @returns A canvas output in blocking mode or a job ID in job mode.\n */\n public abstract generate(\n args: PluginAIInspirationGenerateArgs,\n ): PluginApiReturn<PluginAIInspirationRunResult>\n\n /**\n * Refine/upscale an AI Inspiration source image.\n *\n * @param args - Source shape, optional upscale factor, and run mode.\n * @returns A canvas output in blocking mode or a job ID in job mode.\n */\n public abstract refine(\n args: PluginAIInspirationRefineArgs,\n ): PluginApiReturn<PluginAIInspirationRunResult>\n\n /** Get a transient AI Inspiration job by ID. */\n public abstract getJob(\n args: PluginAIInspirationJobArgs,\n ): PluginApiReturn<PluginAIInspirationGetJobResult>\n\n /** Cancel a transient AI Inspiration job. */\n public abstract cancelJob(\n args: PluginAIInspirationJobArgs,\n ): PluginApiReturn<PluginAIInspirationCancelJobResult>\n\n /** List transient AI Inspiration jobs created in the current host session. */\n public abstract listJobs(): PluginApiReturn<PluginAIInspirationListJobsResult>\n\n /**\n * Get the sanitized workflow graph containing a Present shape.\n *\n * @param args - Object containing `shapeId`.\n * @returns The workflow and matching node, or `null` values when the shape is not in a workflow.\n */\n public abstract getWorkflowForShape(\n args: PluginAIInspirationGetWorkflowForShapeArgs,\n ): PluginApiReturn<PluginAIInspirationGetWorkflowForShapeResult>\n\n /**\n * Build a rerun plan for the selected workflow branch ending at a shape.\n *\n * @param args - Object containing `shapeId`.\n * @returns Ready plan data or an unavailable reason.\n */\n public abstract getSelectedBranchRerunPlan(\n args: PluginAIInspirationGetWorkflowForShapeArgs,\n ): PluginApiReturn<PluginAIInspirationRerunPlanResult>\n\n /**\n * Rerun the selected workflow branch and supersede the previous branch.\n *\n * @param args - Selected shape, optional end frame shape, and run mode.\n * @returns New canvas outputs in blocking mode or a job ID in job mode.\n */\n public abstract rerunSelectedBranch(\n args: PluginAIInspirationRerunSelectedBranchArgs,\n ): PluginApiReturn<PluginAIInspirationRunResult>\n\n /**\n * Extract a reusable recipe draft from the workflow path ending at a shape.\n *\n * @param args - Object containing `shapeId`.\n * @returns A recipe draft or an unavailable reason.\n */\n public abstract extractRecipeFromShape(\n args: PluginAIInspirationExtractRecipeFromShapeArgs,\n ): PluginApiReturn<PluginAIInspirationExtractionResult>\n\n /**\n * List project-level AI Inspiration recipes stored in Present document metadata.\n *\n * @returns Saved project recipes.\n */\n public abstract listRecipes(): PluginApiReturn<PluginAIInspirationListRecipesResult>\n\n /**\n * Save a project-level AI Inspiration recipe.\n *\n * @param args - Recipe draft and desired name.\n * @returns Saved, duplicate, invalid-name, or failed status.\n */\n public abstract saveRecipe(\n args: PluginAIInspirationSaveRecipeArgs,\n ): PluginApiReturn<PluginAIInspirationSaveRecipeResult>\n\n /**\n * Delete a project-level AI Inspiration recipe.\n *\n * @param args - Object containing `recipeId`.\n * @returns Whether a recipe was deleted.\n */\n public abstract deleteRecipe(\n args: PluginAIInspirationDeleteRecipeArgs,\n ): PluginApiReturn<PluginAIInspirationDeleteRecipeResult>\n\n /**\n * Run a saved or inline recipe against Present canvas slot shapes.\n *\n * @param args - Saved `recipeId` or inline `recipe`, slot shape IDs, and run mode.\n * @returns Canvas outputs in blocking mode or a job ID in job mode.\n */\n public abstract runRecipe(\n args: PluginAIInspirationRunRecipeArgs,\n ): PluginApiReturn<PluginAIInspirationRunResult>\n}\n","import { PluginDocumentationAIInspirationApi } from \"./aiInspiration\"\n\n/**\n * Present documentation APIs for Snaptrude plugins.\n *\n * Accessed via `snaptrude.documentation`.\n */\nexport abstract class PluginDocumentationApi {\n /** AI Inspiration image, video, workflow, and recipe APIs. */\n public abstract aiInspiration: PluginDocumentationAIInspirationApi\n\n constructor() {}\n}\n\nexport * from \"./aiInspiration\"\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Buildable Envelope management — create and update parametric zoning envelopes.\n *\n * A **buildable envelope** is the regulated volume inside which a building may\n * be massed. The host owns envelope identity: {@linkcode PluginBuildableEnvelopeApi.create create}\n * mints a `buildableEnvelopeId` and returns it; {@linkcode PluginBuildableEnvelopeApi.update update}\n * requires that id to target the existing envelope.\n *\n * Accessed via `snaptrude.entity.buildableEnvelope`.\n */\nexport abstract class PluginBuildableEnvelopeApi {\n constructor() {}\n\n /**\n * Create a new parametric buildable envelope.\n *\n * @param args - A {@linkcode PluginBuildableEnvelopeCreateArgs} object.\n * @returns A {@linkcode PluginBuildableEnvelopeCreateResult} with the\n * `buildableEnvelopeId` of the created envelope.\n * @throws If validation fails or generation produces no renderable geometry.\n *\n * # Example\n * ```ts\n * const { buildableEnvelopeId } = await snaptrude.entity.buildableEnvelope.create({\n * sitePolygon: [\n * { x: 0, z: 0 },\n * { x: 100, z: 0 },\n * { x: 100, z: 80 },\n * { x: 0, z: 80 },\n * ],\n * lengthUnit: \"ft\",\n * setbacks: [\n * { aboveHeight: 0, front: 10, side: 5, rear: 10 },\n * { aboveHeight: 100, front: 20, side: 10, rear: 20 },\n * ],\n * verticalCap: { kind: \"max_height\", maxHeight: 150 },\n * floorToFloor: 12,\n * })\n * ```\n */\n public abstract create(\n args: PluginBuildableEnvelopeCreateArgs\n ): PluginApiReturn<PluginBuildableEnvelopeCreateResult>\n\n /**\n * Update an existing parametric buildable envelope.\n *\n * @param args - A {@linkcode PluginBuildableEnvelopeUpdateArgs} object.\n * `buildableEnvelopeId` is required and must match an existing envelope on\n * the canvas.\n * @returns A {@linkcode PluginBuildableEnvelopeUpdateResult} with the\n * `buildableEnvelopeId` of the updated envelope.\n * @throws If validation fails, the envelope does not exist, or generation\n * produces no renderable geometry.\n *\n * # Example\n * ```ts\n * const { buildableEnvelopeId } = await snaptrude.entity.buildableEnvelope.update({\n * buildableEnvelopeId: existingId,\n * sitePolygon: [\n * { x: 0, z: 0 },\n * { x: 100, z: 0 },\n * { x: 100, z: 80 },\n * { x: 0, z: 80 },\n * ],\n * lengthUnit: \"ft\",\n * setbacks: [{ aboveHeight: 0, front: 10, side: 5, rear: 10 }],\n * verticalCap: { kind: \"max_height\", maxHeight: 175 },\n * floorToFloor: 12,\n * })\n * ```\n */\n public abstract update(\n args: PluginBuildableEnvelopeUpdateArgs\n ): PluginApiReturn<PluginBuildableEnvelopeUpdateResult>\n}\n\n/**\n * Site polygon vertex in the request `lengthUnit`.\n *\n * Vertices may be passed as `{x, z}` objects or `[x, z]` tuples. Numeric\n * values must be finite (no `NaN` or `±Infinity`).\n */\nexport const PluginBuildableEnvelopePolygonVertex = z.union([\n z.object({ x: z.number().finite(), z: z.number().finite() }).strict(),\n z.tuple([z.number().finite(), z.number().finite()]),\n])\n\nexport type PluginBuildableEnvelopePolygonVertex = z.infer<\n typeof PluginBuildableEnvelopePolygonVertex\n>\n\n/**\n * Vertical cap for a buildable envelope.\n *\n * Use exactly one shape:\n * - `{ kind: \"max_height\", maxHeight }`\n * - `{ kind: \"max_floors\", maxFloors }`\n *\n * Floor-to-floor height is not nested here; it is always supplied as the\n * top-level `floorToFloor` argument.\n */\nexport const PluginBuildableEnvelopeVerticalCap = z.discriminatedUnion(\"kind\", [\n z.object({\n kind: z.literal(\"max_height\"),\n maxHeight: z.number().finite().positive(),\n }).strict(),\n z.object({\n kind: z.literal(\"max_floors\"),\n maxFloors: z.number().finite().int().positive(),\n }).strict(),\n])\n\nexport type PluginBuildableEnvelopeVerticalCap = z.infer<\n typeof PluginBuildableEnvelopeVerticalCap\n>\n\n/**\n * One tier of a buildable envelope's setback profile.\n *\n * Tiers are ordered by `aboveHeight`. The first tier (index 0) must have\n * `aboveHeight: 0` and describes the ground footprint; each subsequent tier\n * describes the complete setback at a strictly greater height. Each tier\n * carries its own `front`, `side`, and `rear` values — there is no\n * inheritance from earlier tiers.\n *\n * All numeric values must be finite and nonnegative, in the request\n * `lengthUnit`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `aboveHeight` | `number` | Height at or above which this tier applies; the ground tier uses `0` |\n * | `front` | `number` | Front setback for this tier |\n * | `side` | `number` | Side setback for this tier |\n * | `rear` | `number` | Rear setback for this tier |\n */\nexport const PluginBuildableEnvelopeSetbackTier = z.object({\n aboveHeight: z.number().finite().nonnegative(),\n front: z.number().finite().nonnegative(),\n side: z.number().finite().nonnegative(),\n rear: z.number().finite().nonnegative(),\n}).strict()\n\nexport type PluginBuildableEnvelopeSetbackTier = z.infer<\n typeof PluginBuildableEnvelopeSetbackTier\n>\n\n// Enforces setback tier ordering invariants on the parsed args shape:\n// - setbacks[0].aboveHeight === 0\n// - aboveHeight strictly increasing thereafter\n// Length >= 1 is enforced earlier by z.array(...).min(1).\nfunction refineSetbackTiers(\n args: { setbacks: PluginBuildableEnvelopeSetbackTier[] },\n ctx: z.RefinementCtx\n): void {\n const tiers = args.setbacks\n if (tiers.length === 0) return\n if (tiers[0].aboveHeight !== 0) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"setbacks\", 0, \"aboveHeight\"],\n message: \"Ground tier required: setbacks[0].aboveHeight must be 0.\",\n })\n }\n for (let i = 1; i < tiers.length; i++) {\n if (!(tiers[i].aboveHeight > tiers[i - 1].aboveHeight)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"setbacks\", i, \"aboveHeight\"],\n message:\n \"Setback tiers must be ordered by strictly increasing aboveHeight.\",\n })\n }\n }\n}\n\n/**\n * Arguments for {@linkcode PluginBuildableEnvelopeApi.create}.\n *\n * Strict schema. The host owns identity — no `buildableEnvelopeId` is accepted\n * on create; the id is minted by the host and returned in\n * {@linkcode PluginBuildableEnvelopeCreateResult}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sitePolygon` | {@linkcode PluginBuildableEnvelopePolygonVertex}`[]` | Site polygon vertices in `lengthUnit`; minimum 3 vertices |\n * | `lengthUnit` | `\"ft\" \\| \"m\"` | Unit used by all length fields |\n * | `setbacks` | {@linkcode PluginBuildableEnvelopeSetbackTier}`[]` | Setback profile, ground tier first; minimum 1 tier |\n * | `verticalCap` | {@linkcode PluginBuildableEnvelopeVerticalCap} | Maximum height or floor count |\n * | `floorToFloor` | `number` | Required floor-to-floor height in `lengthUnit` |\n * | `farRatio` | `number?` | Optional FAR value, positive when provided |\n * | `lotCoverageMaxPct` | `number?` | Optional lot coverage cap, `0..100` |\n */\nexport const PluginBuildableEnvelopeCreateArgs = z\n .object({\n sitePolygon: z.array(PluginBuildableEnvelopePolygonVertex).min(3),\n lengthUnit: z.union([z.literal(\"ft\"), z.literal(\"m\")]),\n setbacks: z.array(PluginBuildableEnvelopeSetbackTier).min(1),\n verticalCap: PluginBuildableEnvelopeVerticalCap,\n floorToFloor: z.number().finite().positive(),\n farRatio: z.number().finite().positive().optional(),\n lotCoverageMaxPct: z.number().finite().min(0).max(100).optional(),\n })\n .strict()\n .superRefine(refineSetbackTiers)\n\nexport type PluginBuildableEnvelopeCreateArgs = z.infer<\n typeof PluginBuildableEnvelopeCreateArgs\n>\n\n/**\n * Result of {@linkcode PluginBuildableEnvelopeApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildableEnvelopeId` | `string` | Non-empty unique ID of the created buildable envelope |\n */\nexport const PluginBuildableEnvelopeCreateResult = z.object({\n buildableEnvelopeId: z.string().min(1),\n}).strict()\n\nexport type PluginBuildableEnvelopeCreateResult = z.infer<\n typeof PluginBuildableEnvelopeCreateResult\n>\n\n/**\n * Arguments for {@linkcode PluginBuildableEnvelopeApi.update}.\n *\n * Strict schema. `buildableEnvelopeId` is required and identifies the prior\n * envelope on the canvas to update.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildableEnvelopeId` | `string` | Existing envelope ID to update; non-empty |\n * | `sitePolygon` | {@linkcode PluginBuildableEnvelopePolygonVertex}`[]` | Site polygon vertices in `lengthUnit`; minimum 3 vertices |\n * | `lengthUnit` | `\"ft\" \\| \"m\"` | Unit used by all length fields |\n * | `setbacks` | {@linkcode PluginBuildableEnvelopeSetbackTier}`[]` | Setback profile, ground tier first; minimum 1 tier |\n * | `verticalCap` | {@linkcode PluginBuildableEnvelopeVerticalCap} | Maximum height or floor count |\n * | `floorToFloor` | `number` | Required floor-to-floor height in `lengthUnit` |\n * | `farRatio` | `number?` | Optional FAR value, positive when provided |\n * | `lotCoverageMaxPct` | `number?` | Optional lot coverage cap, `0..100` |\n */\nexport const PluginBuildableEnvelopeUpdateArgs = z\n .object({\n buildableEnvelopeId: z.string().min(1),\n sitePolygon: z.array(PluginBuildableEnvelopePolygonVertex).min(3),\n lengthUnit: z.union([z.literal(\"ft\"), z.literal(\"m\")]),\n setbacks: z.array(PluginBuildableEnvelopeSetbackTier).min(1),\n verticalCap: PluginBuildableEnvelopeVerticalCap,\n floorToFloor: z.number().finite().positive(),\n farRatio: z.number().finite().positive().optional(),\n lotCoverageMaxPct: z.number().finite().min(0).max(100).optional(),\n })\n .strict()\n .superRefine(refineSetbackTiers)\n\nexport type PluginBuildableEnvelopeUpdateArgs = z.infer<\n typeof PluginBuildableEnvelopeUpdateArgs\n>\n\n/**\n * Result of {@linkcode PluginBuildableEnvelopeApi.update}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildableEnvelopeId` | `string` | Non-empty unique ID of the updated buildable envelope |\n */\nexport const PluginBuildableEnvelopeUpdateResult = z.object({\n buildableEnvelopeId: z.string().min(1),\n}).strict()\n\nexport type PluginBuildableEnvelopeUpdateResult = z.infer<\n typeof PluginBuildableEnvelopeUpdateResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Department management — create and query departments.\n *\n * A **department** is a named, colored grouping applied to spaces.\n * Departments are used to categorize spaces by function (e.g. \"FOH\",\n * \"Emergency\", \"Residential\") and control their visual appearance.\n *\n * Accessed via `snaptrude.entity.department`.\n */\nexport abstract class PluginDepartmentApi {\n constructor() {}\n\n /**\n * Create a new department.\n *\n * @param args - An object containing:\n * - {@linkcode PluginDepartmentCreateArgs.name args.name} — Display name\n * - {@linkcode PluginDepartmentCreateArgs.color args.color} — CSS hex color string (e.g. `\"#b5e1dc\"`)\n * @returns A {@linkcode PluginDepartmentCreateResult} with the `departmentId`\n * of the created department\n * @throws If department creation fails\n *\n * # Example\n * ```ts\n * const { departmentId } = await snaptrude.entity.department.create({\n * name: \"Emergency\",\n * color: \"#f5e68b\",\n * })\n * ```\n */\n public abstract create(\n args: PluginDepartmentCreateArgs\n ): PluginApiReturn<PluginDepartmentCreateResult>\n\n /**\n * Get all departments in the current project.\n *\n * Returns every department including well-known ones (Default, Site, etc.)\n * and user-created departments.\n *\n * @returns A {@linkcode PluginDepartmentGetAllResult} with a `departments` array\n *\n * # Example\n * ```ts\n * const { departments } = await snaptrude.entity.department.getAll()\n * for (const dept of departments) {\n * console.log(dept.id, dept.name, dept.color)\n * }\n * ```\n */\n public abstract getAll(): PluginApiReturn<PluginDepartmentGetAllResult>\n}\n\n/**\n * Arguments for {@linkcode PluginDepartmentApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string` | Display name of the department |\n * | `color` | `string` | CSS hex color string (e.g. `\"#b5e1dc\"`) |\n */\nexport const PluginDepartmentCreateArgs = z.object({\n name: z.string(),\n color: z.string(),\n})\n\nexport type PluginDepartmentCreateArgs = z.infer<\n typeof PluginDepartmentCreateArgs\n>\n\n/**\n * Result of {@linkcode PluginDepartmentApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `departmentId` | `string` | Unique ID of the created department |\n */\nexport const PluginDepartmentCreateResult = z.object({\n departmentId: z.string(),\n})\n\nexport type PluginDepartmentCreateResult = z.infer<\n typeof PluginDepartmentCreateResult\n>\n\n/**\n * A single department entry returned by {@linkcode PluginDepartmentApi.getAll}.\n */\nexport const PluginDepartmentEntry = z.object({\n id: z.string(),\n name: z.string(),\n color: z.string(),\n})\n\nexport type PluginDepartmentEntry = z.infer<typeof PluginDepartmentEntry>\n\n/**\n * Result of {@linkcode PluginDepartmentApi.getAll}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `departments` | {@linkcode PluginDepartmentEntry}`[]` | All departments in the project |\n */\nexport const PluginDepartmentGetAllResult = z.object({\n departments: z.array(PluginDepartmentEntry),\n})\n\nexport type PluginDepartmentGetAllResult = z.infer<\n typeof PluginDepartmentGetAllResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\nimport { PProfile } from \"../core/geom/profile\"\nimport { PCurve } from \"../core/geom/curve\"\n\n/**\n * Reference line management — create, query, and delete reference lines.\n *\n * A **reference line** is a 2D guide line (or arc) in the Snaptrude scene,\n * typically used for grid lines and alignment guides. Reference lines\n * carry properties such as grid tags, labels, and line styles.\n *\n * All methods are **host API calls** that return Promises and support\n * undo/redo via Snaptrude's command system.\n *\n * Accessed via `snaptrude.entity.referenceLine`.\n */\nexport abstract class PluginReferenceLineApi {\n constructor() {}\n\n /**\n * Create multiple reference lines from a profile.\n *\n * Each {@linkcode PCurve} in the given {@linkcode PProfile} becomes\n * a separate reference line. Uses `ReferenceLineConstructor.createFromProfile`\n * internally.\n *\n * @param args - An object containing:\n * - {@linkcode PluginReferenceLineCreateMultiArgs.profile args.profile} — A\n * {@linkcode PProfile} whose curves define the reference lines to create\n * @returns A {@linkcode PluginReferenceLineCreateMultiResult} with the\n * `referenceLineIds` of the created reference lines\n * @throws If reference line creation fails\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n *\n * const l1 = snaptrude.core.geom.line.new(vec3.new(0, 0, 0), vec3.new(10, 0, 0))\n * const l2 = snaptrude.core.geom.line.new(vec3.new(10, 0, 0), vec3.new(10, 0, 10))\n * const profile = snaptrude.core.geom.profile.new([l1, l2])\n *\n * const { referenceLineIds } = await snaptrude.entity.referenceLine.createMulti({\n * profile,\n * })\n * ```\n */\n public abstract createMulti(\n args: PluginReferenceLineCreateMultiArgs\n ): PluginApiReturn<PluginReferenceLineCreateMultiResult>\n\n /**\n * Get properties of a reference line by its ID.\n *\n * Only the properties listed in {@linkcode PluginReferenceLineGetArgs.properties\n * args.properties} are returned — unlisted properties will be `undefined`\n * in the result.\n *\n * @param args - An object containing:\n * - {@linkcode PluginReferenceLineGetArgs.referenceLineId args.referenceLineId} —\n * The unique reference line ID\n * - {@linkcode PluginReferenceLineGetArgs.properties args.properties} — Array of\n * property names to retrieve. See {@linkcode PluginReferenceLineGetProperty}.\n * @returns A partial {@linkcode PluginReferenceLineGetResult} containing only the\n * requested properties\n * @throws If the reference line does not exist\n *\n * # Example\n * ```ts\n * const result = await snaptrude.entity.referenceLine.get({\n * referenceLineId: \"some-ref-line-id\",\n * properties: [\"curve\"],\n * })\n * console.log(result.curve) // PCurve\n * ```\n */\n public abstract get(\n args: PluginReferenceLineGetArgs\n ): PluginApiReturn<PluginReferenceLineGetResult>\n\n /**\n * Get the IDs of all reference lines in the current project.\n *\n * Returns every reference line across all stories.\n * Use the returned IDs with {@linkcode PluginReferenceLineApi.get} to query\n * individual reference line properties.\n *\n * @returns A {@linkcode PluginReferenceLineGetAllResult} with a\n * `referenceLineIds` array\n *\n * # Example\n * ```ts\n * const { referenceLineIds } = await snaptrude.entity.referenceLine.getAll()\n * console.log(`Project has ${referenceLineIds.length} reference lines`)\n * ```\n */\n public abstract getAll(): PluginApiReturn<PluginReferenceLineGetAllResult>\n\n /**\n * Delete a reference line by its ID.\n *\n * Permanently removes the reference line and its associated mesh from\n * the scene. This operation is undoable via Snaptrude's command system.\n *\n * @param args - An object containing:\n * - {@linkcode PluginReferenceLineDeleteArgs.referenceLineId args.referenceLineId} —\n * The unique reference line ID to delete\n * @throws If the reference line does not exist\n *\n * # Example\n * ```ts\n * await snaptrude.entity.referenceLine.delete({\n * referenceLineId: \"some-ref-line-id\",\n * })\n * ```\n */\n public abstract delete(\n args: PluginReferenceLineDeleteArgs\n ): PluginApiReturn<PluginReferenceLineDeleteResult>\n}\n\n/**\n * Arguments for {@linkcode PluginReferenceLineApi.createMulti}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode PProfile} | Profile whose curves define reference lines |\n */\nexport const PluginReferenceLineCreateMultiArgs = z.object({\n profile: PProfile,\n})\n\nexport type PluginReferenceLineCreateMultiArgs = z.infer<typeof PluginReferenceLineCreateMultiArgs>\n\n/**\n * Result of {@linkcode PluginReferenceLineApi.createMulti}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `referenceLineIds` | `string[]` | IDs of the created reference lines |\n */\nexport const PluginReferenceLineCreateMultiResult = z.object({\n referenceLineIds: z.array(z.string()),\n})\n\nexport type PluginReferenceLineCreateMultiResult = z.infer<typeof PluginReferenceLineCreateMultiResult>\n\n/**\n * Available properties that can be queried on a reference line.\n *\n * | Value | Return Type | Description |\n * |---|---|---|\n * | `\"curve\"` | {@linkcode PCurve} | The curve geometry of the reference line |\n */\nexport const PluginReferenceLineGetProperty = z.enum([\n \"curve\",\n])\n\n/**\n * Arguments for {@linkcode PluginReferenceLineApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `referenceLineId` | `string` | The reference line ID to query |\n * | `properties` | {@linkcode PluginReferenceLineGetProperty}`[]` | Properties to retrieve |\n */\nexport const PluginReferenceLineGetArgs = z.object({\n referenceLineId: z.string(),\n properties: z.array(PluginReferenceLineGetProperty),\n})\n\nexport type PluginReferenceLineGetArgs = z.infer<typeof PluginReferenceLineGetArgs>\n\n/**\n * Result of {@linkcode PluginReferenceLineApi.get}.\n *\n * A partial object — only the properties that were requested in\n * {@linkcode PluginReferenceLineGetArgs.properties} will be present.\n */\nexport const PluginReferenceLineGetResult = z\n .object({\n curve: PCurve,\n })\n .partial()\n\nexport type PluginReferenceLineGetResult = z.infer<typeof PluginReferenceLineGetResult>\n\n/**\n * Result of {@linkcode PluginReferenceLineApi.getAll}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `referenceLineIds` | `string[]` | IDs of all reference lines in the project |\n */\nexport const PluginReferenceLineGetAllResult = z.object({\n referenceLineIds: z.array(z.string()),\n})\n\nexport type PluginReferenceLineGetAllResult = z.infer<typeof PluginReferenceLineGetAllResult>\n\n/**\n * Arguments for {@linkcode PluginReferenceLineApi.delete}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `referenceLineId` | `string` | The reference line ID to delete |\n */\nexport const PluginReferenceLineDeleteArgs = z.object({\n referenceLineId: z.string(),\n})\n\nexport type PluginReferenceLineDeleteArgs = z.infer<typeof PluginReferenceLineDeleteArgs>\n\n/** Result type for {@linkcode PluginReferenceLineApi.delete} — returns nothing on success. */\nexport type PluginReferenceLineDeleteResult = void\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\nimport { PVec3 } from \"../core/math/vec3\"\nimport { PQuat } from \"../core/math/quat\"\nimport { PProfile } from \"../core/geom/profile\"\n\n/**\n * Space (room/mass) management — create, query, update, and delete spaces.\n *\n * A **space** is a 3D volume representing a room or mass in the\n * Snaptrude scene. Spaces live on a particular story and carry\n * properties such as name, area, department, and room type.\n *\n * All methods are **host API calls** that return Promises and support\n * undo/redo via Snaptrude's command system.\n *\n * Accessed via `snaptrude.entity.space`.\n */\nexport abstract class PluginSpaceApi {\n constructor() {}\n\n /**\n * Create a rectangular (box) space.\n *\n * Generates an axis-aligned box with the given dimensions at the\n * specified position. The created space is automatically assigned\n * to the active story and a default department.\n *\n * @param args - An object containing:\n * - {@linkcode PluginSpaceCreateRectangularArgs.position args.position} — Origin\n * position as a {@linkcode PVec3} in Babylon units\n * - {@linkcode PluginSpaceCreateRectangularArgs.dimensions args.dimensions} — Box\n * dimensions `{ width, height, depth }` in Babylon units\n * @returns A {@linkcode PluginSpaceCreateRectangularResult} with the `spaceId`\n * of the created space\n * @throws If space creation fails\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n *\n * const { spaceId } = await snaptrude.entity.space.createRectangular({\n * position: vec3.new(0, 0, 0),\n * dimensions: { width: 5, height: 3, depth: 4 },\n * })\n * ```\n */\n public abstract createRectangular({\n position,\n dimensions,\n }: PluginSpaceCreateRectangularArgs): PluginApiReturn<PluginSpaceCreateRectangularResult>\n\n /**\n * Create a space by extruding a 2D profile.\n *\n * The {@linkcode PluginSpaceCreateFromProfileArgs.profile profile} is used as\n * the outer boundary and extruded upward (along the Y axis) by\n * {@linkcode PluginSpaceCreateFromProfileArgs.extrudeHeight extrudeHeight},\n * then offset by {@linkcode PluginSpaceCreateFromProfileArgs.position\n * position}. Optional {@linkcode PluginSpaceCreateFromProfileArgs.innerProfiles\n * innerProfiles} are used as holes inside the outer boundary. The created\n * space is automatically assigned to the active story and a default department.\n *\n * Use {@linkcode PluginProfileApi.fromLinePoints} to quickly build a profile\n * from a list of points.\n *\n * @param args - An object containing:\n * - {@linkcode PluginSpaceCreateFromProfileArgs.profile args.profile} — A closed\n * {@linkcode PProfile} defining the outer floor shape\n * - {@linkcode PluginSpaceCreateFromProfileArgs.innerProfiles args.innerProfiles} —\n * Optional closed {@linkcode PProfile}`[]` loops to subtract as holes\n * - {@linkcode PluginSpaceCreateFromProfileArgs.extrudeHeight args.extrudeHeight} —\n * Extrusion height in Babylon units\n * - {@linkcode PluginSpaceCreateFromProfileArgs.position args.position} — Offset\n * position as a {@linkcode PVec3} in Babylon units\n * @returns A {@linkcode PluginSpaceCreateFromProfileResult} with the `spaceId`\n * of the created space\n * @throws If the profile is invalid or mesh creation fails\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n *\n * const outerProfile = await snaptrude.core.geom.profile.fromLinePoints({\n * points: [\n * vec3.new(0, 0, 0),\n * vec3.new(10, 0, 0),\n * vec3.new(10, 0, 8),\n * vec3.new(0, 0, 8),\n * ],\n * })\n * const holeProfile = await snaptrude.core.geom.profile.fromLinePoints({\n * points: [\n * vec3.new(3, 0, 3),\n * vec3.new(7, 0, 3),\n * vec3.new(7, 0, 5),\n * vec3.new(3, 0, 5),\n * ],\n * })\n *\n * const { spaceId } = await snaptrude.entity.space.createFromProfile({\n * profile: outerProfile,\n * innerProfiles: [holeProfile],\n * extrudeHeight: 3,\n * position: vec3.new(0, 0, 0),\n * })\n * ```\n */\n public abstract createFromProfile({\n profile,\n innerProfiles,\n extrudeHeight,\n position,\n }: PluginSpaceCreateFromProfileArgs): PluginApiReturn<PluginSpaceCreateFromProfileResult>\n\n /**\n * Update a space's BRep and mesh geometry by extruding a 2D profile.\n *\n * The {@linkcode PluginSpaceUpdateGeometryFromProfileArgs.profile profile} is\n * extruded upward (along the Y axis) by\n * {@linkcode PluginSpaceUpdateGeometryFromProfileArgs.extrudeHeight extrudeHeight}\n * and applied to the existing space. The space keeps the same `spaceId`,\n * metadata, department, and transform; only its geometry is replaced.\n *\n * Profile points are interpreted in scene coordinates. Profiles returned by\n * {@linkcode PluginSpaceApi.get} with `\"profile\"` can be passed back directly;\n * `\"planPoints\"` can be used to construct line-only profiles in the same X/Z\n * plan coordinate space.\n *\n * Use {@linkcode PluginProfileApi.fromLinePoints} to quickly build a profile\n * from a list of points.\n *\n * @param args - An object containing:\n * - {@linkcode PluginSpaceUpdateGeometryFromProfileArgs.spaceId args.spaceId} —\n * The unique space ID to update\n * - {@linkcode PluginSpaceUpdateGeometryFromProfileArgs.profile args.profile} —\n * A closed {@linkcode PProfile} defining the new floor shape\n * - {@linkcode PluginSpaceUpdateGeometryFromProfileArgs.extrudeHeight\n * args.extrudeHeight} — New extrusion height in Babylon units\n * @returns A {@linkcode PluginSpaceUpdateGeometryFromProfileResult} with the\n * `spaceId` of the updated space\n * @throws If the space does not exist, the component is not a space/mass, the\n * height is not positive, or the profile cannot create valid geometry\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n *\n * const profile = await snaptrude.core.geom.profile.fromLinePoints({\n * points: [\n * vec3.new(0, 0, 0),\n * vec3.new(12, 0, 0),\n * vec3.new(12, 0, 6),\n * vec3.new(0, 0, 6),\n * ],\n * })\n *\n * const { spaceId } = await snaptrude.entity.space.updateGeometryFromProfile({\n * spaceId: \"some-space-id\",\n * profile,\n * extrudeHeight: 4,\n * })\n * ```\n */\n public abstract updateGeometryFromProfile({\n spaceId,\n profile,\n extrudeHeight,\n }: PluginSpaceUpdateGeometryFromProfileArgs): PluginApiReturn<PluginSpaceUpdateGeometryFromProfileResult>\n\n /**\n * Get the IDs of all spaces in the current project.\n *\n * Returns every space (mass that is not a building) across all stories.\n * Use the returned IDs with {@linkcode PluginSpaceApi.get} to query\n * individual space properties.\n *\n * @returns A {@linkcode PluginSpaceGetAllResult} with a `spacesIds` array\n *\n * # Example\n * ```ts\n * const { spacesIds } = await snaptrude.entity.space.getAll()\n * console.log(`Project has ${spacesIds.length} spaces`)\n * ```\n */\n public abstract getAll(): PluginApiReturn<PluginSpaceGetAllResult>\n\n /**\n * Get properties of a space by its ID.\n *\n * Only the properties listed in {@linkcode PluginSpaceGetArgs.properties\n * args.properties} are returned — unlisted properties will be `undefined`\n * in the result.\n *\n * @param args - An object containing:\n * - {@linkcode PluginSpaceGetArgs.spaceId args.spaceId} — The unique space ID\n * (as returned by creation methods or {@linkcode PluginSpaceApi.getAll})\n * - {@linkcode PluginSpaceGetArgs.properties args.properties} — Array of property\n * names to retrieve. See {@linkcode PluginSpaceGetProperty} for available values.\n * @returns A partial {@linkcode PluginSpaceGetResult} containing only the requested\n * properties\n * @throws If the space does not exist or the component is not a space/mass\n *\n * # Example\n * ```ts\n * const info = await snaptrude.entity.space.get({\n * spaceId: \"some-space-id\",\n * properties: [\"name\", \"area\", \"position\"],\n * })\n * console.log(info.name, info.area, info.position)\n * ```\n */\n public abstract get({\n spaceId,\n properties,\n }: PluginSpaceGetArgs): PluginApiReturn<PluginSpaceGetResult>\n\n /**\n * Delete a space by its ID.\n *\n * Permanently removes the space and its associated mesh from the scene.\n * This operation is undoable via Snaptrude's command system.\n *\n * @param args - An object containing:\n * - {@linkcode PluginSpaceDeleteArgs.spaceId args.spaceId} — The unique space ID\n * to delete\n * @throws If the space does not exist or the component is not a space/mass\n *\n * # Example\n * ```ts\n * await snaptrude.entity.space.delete({ spaceId: \"some-space-id\" })\n * ```\n */\n public abstract delete({\n spaceId,\n }: PluginSpaceDeleteArgs): PluginApiReturn<PluginSpaceDeleteResult>\n\n /**\n * Update properties of a space by its ID.\n *\n * Only the properties provided in {@linkcode PluginSpaceUpdateArgs.properties\n * args.properties} will be updated — omitted properties remain unchanged.\n * This operation is undoable via Snaptrude's command system.\n *\n * @param args - An object containing:\n * - {@linkcode PluginSpaceUpdateArgs.spaceId args.spaceId} — The unique space ID\n * to update\n * - {@linkcode PluginSpaceUpdateArgs.properties args.properties} — Key/value pairs\n * of properties to update. See {@linkcode PluginSpaceUpdateArgs} for supported fields.\n * @returns A {@linkcode PluginSpaceUpdateResult} echoing back the `spaceId` and\n * the updated property values\n * @throws If the space does not exist or the component is not a space/mass\n *\n * # Example\n * ```ts\n * const result = await snaptrude.entity.space.update({\n * spaceId: \"some-space-id\",\n * properties: {\n * room_type: \"Kitchen\",\n * massType: \"Room\",\n * departmentId: \"CORE\",\n * },\n * })\n * ```\n */\n public abstract update(\n args: PluginSpaceUpdateArgs,\n ): PluginApiReturn<PluginSpaceUpdateResult>\n\n /**\n * Create many spaces in a single undoable operation.\n *\n * Each item is either a rectangular box (`kind: \"rectangular\"`) or an\n * extruded profile (`kind: \"profile\"`), and may optionally set `room_type`,\n * `spaceType`, `massType`, and `departmentId`. All creations — and the\n * optional property assignments — are batched into **one** command, so the\n * entire batch is undone/redone in a single step.\n *\n * All items are validated first; if any item is invalid the call **throws**\n * and no spaces are created (nothing is applied) — consistent with the\n * single-item create methods.\n *\n * @param args - {@linkcode PluginSpaceBulkCreateArgs} with an `items` array\n * @returns A {@linkcode PluginSpaceBulkCreateResult} with the `spaceIds` of\n * the created spaces, in input order\n * @throws If any item has invalid dimensions, height, or profile\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n *\n * const { spaceIds } = await snaptrude.entity.space.bulkCreate({\n * items: [\n * {\n * kind: \"rectangular\",\n * position: vec3.new(0, 0, 0),\n * dimensions: { width: 5, height: 3, depth: 4 },\n * spaceType: \"Room\",\n * departmentId: \"CORE\",\n * },\n * {\n * kind: \"profile\",\n * profile: await snaptrude.core.geom.profile.fromLinePoints({\n * points: [vec3.new(0, 0, 0), vec3.new(8, 0, 0), vec3.new(8, 0, 6), vec3.new(0, 0, 6)],\n * }),\n * extrudeHeight: 3,\n * position: vec3.new(10, 0, 0),\n * massType: \"Room\",\n * },\n * ],\n * })\n * ```\n */\n public abstract bulkCreate(\n args: PluginSpaceBulkCreateArgs,\n ): PluginApiReturn<PluginSpaceBulkCreateResult>\n\n /**\n * Update many existing spaces in a single undoable operation.\n *\n * Each item targets an existing space by `spaceId` and may change its\n * geometry (`profile` + `extrudeHeight`, which must be supplied together) and/or\n * its `properties` (`room_type`, `massType`, `spaceType`, `areaClass`,\n * `departmentId` —\n * nested under `properties`, mirroring {@linkcode PluginSpaceApi.update}). All\n * changes are batched into **one** command, so the entire batch is\n * undone/redone in a single step.\n *\n * All items are validated first; if any item is invalid — an unknown\n * `spaceId`, a non-positive height, or supplying only one of\n * `profile`/`extrudeHeight` — the call **throws** and no changes are applied.\n *\n * @param args - {@linkcode PluginSpaceBulkUpdateArgs} with an `items` array\n * @returns A {@linkcode PluginSpaceBulkUpdateResult} echoing one\n * {@linkcode PluginSpaceUpdateResult} per item in `spaces`, in input order\n * @throws If any item targets an unknown space, has a non-positive height, or\n * supplies only one of `profile`/`extrudeHeight`\n *\n * # Example\n * ```ts\n * const { spaces } = await snaptrude.entity.space.bulkUpdate({\n * items: [\n * { spaceId: \"space-a\", properties: { room_type: \"Kitchen\", spaceType: \"Room\" } },\n * { spaceId: \"space-b\", profile, extrudeHeight: 4 },\n * ],\n * })\n * ```\n */\n public abstract bulkUpdate(\n args: PluginSpaceBulkUpdateArgs,\n ): PluginApiReturn<PluginSpaceBulkUpdateResult>\n\n /**\n * Delete many spaces in a single undoable operation.\n *\n * All deletions are batched into **one** command, so the entire batch is\n * undone/redone in a single step.\n *\n * All IDs are validated first; if any ID is unknown or is not a space the\n * call **throws** and no spaces are deleted — consistent with the single-item\n * {@linkcode PluginSpaceApi.delete}.\n *\n * @param args - {@linkcode PluginSpaceBulkDeleteArgs} with a `spaceIds` array\n * @returns A {@linkcode PluginSpaceBulkDeleteResult} with `deletedSpaceIds`\n * (the removed IDs, in input order)\n * @throws If any ID does not resolve to an existing space\n *\n * # Example\n * ```ts\n * await snaptrude.entity.space.bulkDelete({ spaceIds: [\"space-a\", \"space-b\"] })\n * ```\n */\n public abstract bulkDelete(\n args: PluginSpaceBulkDeleteArgs,\n ): PluginApiReturn<PluginSpaceBulkDeleteResult>\n}\n\n/**\n * Arguments for {@linkcode PluginSpaceApi.createRectangular}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `position` | {@linkcode PVec3} | Origin position in Babylon units |\n * | `dimensions` | `{ width, height, depth }` | Box dimensions in Babylon units |\n */\nexport const PluginSpaceCreateRectangularArgs = z.object({\n position: PVec3,\n dimensions: z.object({\n width: z.number(),\n height: z.number(),\n depth: z.number(),\n }),\n})\n\nexport type PluginSpaceCreateRectangularArgs = z.infer<\n typeof PluginSpaceCreateRectangularArgs\n>\n\n/**\n * Result of {@linkcode PluginSpaceApi.createRectangular}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | Unique ID of the created space |\n */\nexport const PluginSpaceCreateRectangularResult = z.object({\n spaceId: z.string(),\n})\n\nexport type PluginSpaceCreateRectangularResult = z.infer<\n typeof PluginSpaceCreateRectangularResult\n>\n\n/**\n * Arguments for {@linkcode PluginSpaceApi.createFromProfile}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode PProfile} | Closed 2D profile defining the outer floor shape |\n * | `innerProfiles` | {@linkcode PProfile}`[]` | Optional closed profiles to subtract as holes |\n * | `extrudeHeight` | `number` | Extrusion height in Babylon units |\n * | `position` | {@linkcode PVec3} | Offset position in Babylon units |\n */\nexport const PluginSpaceCreateFromProfileArgs = z.object({\n profile: PProfile,\n innerProfiles: z.array(PProfile).optional(),\n extrudeHeight: z.number(),\n position: PVec3,\n})\n\nexport type PluginSpaceCreateFromProfileArgs = z.infer<\n typeof PluginSpaceCreateFromProfileArgs\n>\n\n/**\n * Result of {@linkcode PluginSpaceApi.createFromProfile}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | Unique ID of the created space |\n */\nexport const PluginSpaceCreateFromProfileResult = z.object({\n spaceId: z.string(),\n})\n\nexport type PluginSpaceCreateFromProfileResult = z.infer<\n typeof PluginSpaceCreateFromProfileResult\n>\n\n/**\n * Arguments for {@linkcode PluginSpaceApi.updateGeometryFromProfile}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | Space to update |\n * | `profile` | {@linkcode PProfile} | Closed 2D profile defining the new floor shape |\n * | `extrudeHeight` | `number` | New extrusion height in Babylon units |\n */\nexport const PluginSpaceUpdateGeometryFromProfileArgs = z.object({\n spaceId: z.string(),\n profile: PProfile,\n extrudeHeight: z.number(),\n})\n\nexport type PluginSpaceUpdateGeometryFromProfileArgs = z.infer<\n typeof PluginSpaceUpdateGeometryFromProfileArgs\n>\n\n/**\n * Result of {@linkcode PluginSpaceApi.updateGeometryFromProfile}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | Unique ID of the updated space |\n */\nexport const PluginSpaceUpdateGeometryFromProfileResult = z.object({\n spaceId: z.string(),\n})\n\nexport type PluginSpaceUpdateGeometryFromProfileResult = z.infer<\n typeof PluginSpaceUpdateGeometryFromProfileResult\n>\n\n/**\n * Available properties that can be queried on a space.\n *\n * **Basic:**\n * | Value | Return Type | Description |\n * |---|---|---|\n * | `\"id\"` | `string` | Unique space identifier |\n * | `\"type\"` | `string` | Component type |\n * | `\"room_type\"` | `string` | Room type classification |\n * | `\"name\"` | `string` | Display name of the space |\n *\n * **Derived from parametric data:**\n * | Value | Return Type | Description |\n * |---|---|---|\n * | `\"area\"` | `number` | Bottom face area (from `areas_bottomFace`) |\n * | `\"breadth\"` | `number` | Breadth dimension |\n * | `\"depth\"` | `number` | Depth dimension |\n * | `\"height\"` | `number` | Height dimension |\n * | `\"massType\"` | `string \\| null` | Mass type classification |\n * | `\"spaceType\"` | `string \\| null` | Space type classification (Room, Balcony, etc.) |\n * | `\"areaClass\"` | {@linkcode PluginAreaClass} | Effective area classification (`\"NET\"`, `\"GROSS\"`, or `\"EXCLUDED\"`), resolving any per-space override then the space-type default. Never null. |\n * | `\"storey\"` | `number \\| null` | Story the space belongs to |\n * | `\"departmentId\"` | `string \\| null` | Assigned department ID |\n * | `\"departmentName\"` | `string` | Assigned department name |\n * | `\"departmentColor\"` | `string` | Assigned department color (hex/CSS) |\n *\n * **Derived from mesh:**\n * | Value | Return Type | Description |\n * |---|---|---|\n * | `\"position\"` | {@linkcode PVec3} | Local position relative to parent |\n * | `\"absolutePosition\"` | {@linkcode PVec3} | Absolute position in the scene |\n * | `\"rotation\"` | {@linkcode PVec3} | Euler rotation angles (radians) |\n * | `\"rotationQuaternion\"` | {@linkcode PQuat} \\| `null` | Quaternion rotation, or `null` if unset |\n *\n * **Derived from brep:**\n * | Value | Return Type | Description |\n * |---|---|---|\n * | `\"planPoints\"` | {@linkcode PVec3}`[]` | Bottom outer profile points in world space with `y = 0` (2D plan). No closing duplicate point. |\n * | `\"profile\"` | {@linkcode PProfile} | Bottom outer profile in world space, preserving line/arc curve data. |\n * | `\"innerProfiles\"` | {@linkcode PProfile}`[]` | Bottom inner profiles (holes) in world space, preserving line/arc curve data. Empty array when the space has no holes. |\n * | `\"innerPlanPoints\"` | {@linkcode PVec3}`[][]` | One point loop per inner profile (hole) in world space with `y = 0` (2D plan). No closing duplicate point. Empty array when the space has no holes. |\n */\nexport const PluginSpaceGetProperty = z.enum([\n // Basic\n \"id\",\n \"type\",\n \"room_type\",\n \"name\",\n // Derived from parametric data\n \"area\",\n \"breadth\",\n \"depth\",\n \"height\",\n \"massType\",\n \"spaceType\",\n \"areaClass\",\n \"storey\",\n \"departmentId\",\n \"departmentName\",\n \"departmentColor\",\n // Derived from mesh\n \"position\",\n \"absolutePosition\",\n \"rotation\",\n \"rotationQuaternion\",\n // Derived from brep\n \"planPoints\",\n \"profile\",\n \"innerProfiles\",\n \"innerPlanPoints\",\n // Derived from adjacency manager\n \"adjacency\",\n])\n\n/**\n * Arguments for {@linkcode PluginSpaceApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | The space ID to query |\n * | `properties` | {@linkcode PluginSpaceGetProperty}`[]` | Properties to retrieve |\n */\nexport const PluginSpaceGetArgs = z.object({\n spaceId: z.string(),\n properties: z.array(PluginSpaceGetProperty),\n})\n\nexport type PluginSpaceGetArgs = z.infer<typeof PluginSpaceGetArgs>\n\n/**\n * Supported space type values.\n *\n * Mirrors the internal `SpaceType` enum from `spaceType.types.ts`.\n *\n * | Value | Description |\n * |---|---|\n * | `\"Room\"` | Standard room |\n * | `\"Program Block\"` | Program/department block |\n * | `\"Balcony\"` | Balcony space |\n * | `\"Road\"` | Road |\n * | `\"Garden\"` | Garden area |\n * | `\"Deck\"` | Deck |\n * | `\"Pool\"` | Pool |\n * | `\"Walkway\"` | Walkway |\n * | `\"Envelope\"` | Envelope |\n * | `\"Parking\"` | Parking area |\n */\nexport const PluginSpaceType = z.enum([\n \"Room\",\n \"Program Block\",\n \"Balcony\",\n \"Road\",\n \"Garden\",\n \"Deck\",\n \"Pool\",\n \"Walkway\",\n \"Envelope\",\n \"Parking\",\n])\n\n/**\n * Area classification for a space — controls which area total the space's\n * footprint contributes to.\n *\n * | Value | Description |\n * |---|---|\n * | `\"NET\"` | Counted toward the net (carpet) area total |\n * | `\"GROSS\"` | Counted toward the gross (built-up) area total |\n * | `\"EXCLUDED\"` | Counted toward neither total |\n *\n * The classification does **not** change a space's own footprint area — it\n * only decides which project-level total that footprint is summed into.\n */\nexport const PluginAreaClass = z.enum([\"NET\", \"GROSS\", \"EXCLUDED\"])\n\n/**\n * Result of {@linkcode PluginSpaceApi.get}.\n *\n * A partial object — only the properties that were requested in\n * {@linkcode PluginSpaceGetArgs.properties} will be present.\n */\nexport const PluginSpaceGetResult = z\n .object({\n // Basic\n id: z.string(),\n type: z.string(),\n room_type: z.string(),\n name: z.string(),\n // Derived from parametric data\n area: z.number(),\n breadth: z.number(),\n depth: z.number(),\n height: z.number(),\n massType: z.string().nullable(),\n spaceType: PluginSpaceType.nullable(),\n areaClass: PluginAreaClass,\n storey: z.number().nullable(),\n departmentId: z.string().nullable(),\n departmentName: z.string(),\n departmentColor: z.string(),\n // Derived from mesh\n position: PVec3,\n absolutePosition: PVec3,\n rotation: PVec3,\n rotationQuaternion: PQuat.nullable(),\n // Derived from brep\n planPoints: z.array(PVec3),\n profile: PProfile,\n innerProfiles: z.array(PProfile),\n innerPlanPoints: z.array(z.array(PVec3)),\n // Derived from adjacency manager\n adjacency: z.array(z.object({\n spaceId: z.string(),\n value: z.number(),\n })),\n })\n .partial()\n\nexport type PluginSpaceGetResult = z.infer<typeof PluginSpaceGetResult>\n\n/**\n * Result of {@linkcode PluginSpaceApi.getAll}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spacesIds` | `string[]` | IDs of all spaces in the project |\n */\nexport const PluginSpaceGetAllResult = z.object({\n spacesIds: z.array(z.string()),\n})\n\nexport type PluginSpaceGetAllResult = z.infer<typeof PluginSpaceGetAllResult>\n\n/**\n * Arguments for {@linkcode PluginSpaceApi.delete}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | The space ID to delete |\n */\nexport const PluginSpaceDeleteArgs = z.object({\n spaceId: z.string(),\n})\n\nexport type PluginSpaceDeleteArgs = z.infer<typeof PluginSpaceDeleteArgs>\n\n/** Result type for {@linkcode PluginSpaceApi.delete} — returns nothing on success. */\nexport type PluginSpaceDeleteResult = void\n\n/**\n * Supported mass type values for {@linkcode PluginSpaceUpdateArgs.properties.massType}.\n *\n * Mirrors the internal `MASS_TYPES` enum.\n *\n * | Value | Description |\n * |---|---|\n * | `\"Plinth\"` | Plinth mass |\n * | `\"Void\"` | Void/cut-out |\n * | `\"Pergola\"` | Pergola structure |\n * | `\"Furniture\"` | Furniture element |\n * | `\"Facade element\"` | Facade element |\n * | `\"Generic mass\"` | Generic mass |\n * | `\"Room\"` | Room (default for spaces) |\n * | `\"Department\"` | Department block |\n * | `\"Building\"` | Building envelope |\n * | `\"Revit Import\"` | Imported from Revit |\n * | `\"Mass\"` | Generic mass type |\n * | `\"Site\"` | Site object |\n */\nexport const PluginMassType = z.enum([\n \"Plinth\",\n \"Void\",\n \"Pergola\",\n \"Furniture\",\n \"Facade element\",\n \"Generic mass\",\n \"Room\",\n \"Department\",\n \"Building\",\n \"Revit Import\",\n \"Mass\",\n \"Site\",\n])\n\n/**\n * Well-known (built-in) department IDs.\n *\n * | Value | Department |\n * |---|---|\n * | `\"DEFAULT\"` | Default department |\n * | `\"SITE\"` | Site department |\n * | `\"ENVELOPE\"` | Envelope department |\n * | `\"CORE\"` | Core department |\n */\nexport const PluginWellKnownDepartmentId = z.enum([\n \"DEFAULT\",\n \"SITE\",\n \"ENVELOPE\",\n \"CORE\",\n])\n\n/**\n * Accepted department ID values — either a {@linkcode PluginWellKnownDepartmentId}\n * or a UUID string for custom (user-created) departments.\n */\nexport const PluginDepartmentId = z.union([\n PluginWellKnownDepartmentId,\n z.uuid(),\n])\n\n/**\n * Arguments for {@linkcode PluginSpaceApi.update}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | The space ID to update |\n * | `properties` | `object` | Key/value pairs of properties to update (all optional) |\n * | `properties.room_type` | `string?` | New room type label |\n * | `properties.massType` | {@linkcode PluginMassType}`?` | New mass type |\n * | `properties.areaClass` | {@linkcode PluginAreaClass}`?` | New area classification. Sets an explicit per-space override (`\"NET\"`, `\"GROSS\"`, or `\"EXCLUDED\"`) that wins over the space-type default. |\n * | `properties.departmentId` | {@linkcode PluginDepartmentId}`?` | New department ID |\n */\nexport const PluginSpaceUpdateArgs = z.object({\n spaceId: z.string(),\n properties: z.object({\n room_type: z.string().optional(),\n massType: PluginMassType.optional(),\n spaceType: PluginSpaceType.optional(),\n areaClass: PluginAreaClass.optional(),\n departmentId: PluginDepartmentId.optional(),\n }),\n})\n\nexport type PluginSpaceUpdateArgs = z.infer<typeof PluginSpaceUpdateArgs>\n\n/**\n * Result of {@linkcode PluginSpaceApi.update}.\n *\n * Echoes back the `spaceId` and the values of properties that were updated.\n * Properties that were not included in the update request will be `undefined`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | The space ID that was updated |\n * | `room_type` | `string?` | Updated room type (if changed) |\n * | `massType` | `string?` | Updated mass type (if changed) |\n * | `spaceType` | `string?` | Updated space type (if changed) |\n * | `areaClass` | {@linkcode PluginAreaClass}`?` | Updated area classification (if changed) |\n * | `departmentId` | `string \\| null?` | Updated department ID (if changed) |\n */\nexport const PluginSpaceUpdateResult = z.object({\n spaceId: z.string(),\n room_type: z.string().optional(),\n massType: z.string().optional(),\n spaceType: z.string().optional(),\n areaClass: PluginAreaClass.optional(),\n departmentId: z.string().nullable().optional(),\n})\n\nexport type PluginSpaceUpdateResult = z.infer<typeof PluginSpaceUpdateResult>\n\n// ---------------------------------------------------------------------------\n// Bulk operations\n// ---------------------------------------------------------------------------\n\n/**\n * A single item for {@linkcode PluginSpaceApi.bulkCreate}.\n *\n * Discriminated on `kind`:\n * - `\"rectangular\"` — a box defined by `position` + `dimensions` (mirrors\n * {@linkcode PluginSpaceCreateRectangularArgs})\n * - `\"profile\"` — an extruded `profile` (with optional `innerProfiles`) by\n * `extrudeHeight` at `position` (mirrors {@linkcode PluginSpaceCreateFromProfileArgs})\n *\n * Every item may optionally set `room_type`, `spaceType`, `massType`, and\n * `departmentId`; these are applied within the same single undo step as the\n * creation.\n */\nexport const PluginSpaceBulkCreateItem = z.discriminatedUnion(\"kind\", [\n z.object({\n kind: z.literal(\"rectangular\"),\n position: PVec3,\n dimensions: z.object({\n width: z.number(),\n height: z.number(),\n depth: z.number(),\n }),\n room_type: z.string().optional(),\n spaceType: PluginSpaceType.optional(),\n massType: PluginMassType.optional(),\n departmentId: PluginDepartmentId.optional(),\n }),\n z.object({\n kind: z.literal(\"profile\"),\n profile: PProfile,\n innerProfiles: z.array(PProfile).optional(),\n extrudeHeight: z.number(),\n position: PVec3,\n room_type: z.string().optional(),\n spaceType: PluginSpaceType.optional(),\n massType: PluginMassType.optional(),\n departmentId: PluginDepartmentId.optional(),\n }),\n])\n\nexport type PluginSpaceBulkCreateItem = z.infer<typeof PluginSpaceBulkCreateItem>\n\n/**\n * Arguments for {@linkcode PluginSpaceApi.bulkCreate}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `items` | {@linkcode PluginSpaceBulkCreateItem}`[]` | Spaces to create |\n */\nexport const PluginSpaceBulkCreateArgs = z.object({\n items: z.array(PluginSpaceBulkCreateItem),\n})\n\nexport type PluginSpaceBulkCreateArgs = z.infer<typeof PluginSpaceBulkCreateArgs>\n\n/**\n * Result of {@linkcode PluginSpaceApi.bulkCreate}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceIds` | `string[]` | IDs of the created spaces, in input order |\n */\nexport const PluginSpaceBulkCreateResult = z.object({\n spaceIds: z.array(z.string()),\n})\n\nexport type PluginSpaceBulkCreateResult = z.infer<\n typeof PluginSpaceBulkCreateResult\n>\n\n/**\n * A single item for {@linkcode PluginSpaceApi.bulkUpdate}.\n *\n * Targets an existing space by `spaceId`. Geometry fields `profile` and\n * `extrudeHeight` must be supplied **together** (mirrors\n * {@linkcode PluginSpaceUpdateGeometryFromProfileArgs}). Property changes are\n * nested under `properties`, mirroring {@linkcode PluginSpaceUpdateArgs}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | The space to update |\n * | `profile` | {@linkcode PProfile}`?` | New floor shape (requires `extrudeHeight`) |\n * | `extrudeHeight` | `number?` | New extrusion height (requires `profile`) |\n * | `properties` | `object?` | Property changes (same shape as {@linkcode PluginSpaceUpdateArgs.properties}) |\n */\nexport const PluginSpaceBulkUpdateItem = z.object({\n spaceId: z.string(),\n profile: PProfile.optional(),\n extrudeHeight: z.number().optional(),\n properties: z\n .object({\n room_type: z.string().optional(),\n massType: PluginMassType.optional(),\n spaceType: PluginSpaceType.optional(),\n areaClass: PluginAreaClass.optional(),\n departmentId: PluginDepartmentId.optional(),\n })\n .optional(),\n})\n\nexport type PluginSpaceBulkUpdateItem = z.infer<typeof PluginSpaceBulkUpdateItem>\n\n/**\n * Arguments for {@linkcode PluginSpaceApi.bulkUpdate}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `items` | {@linkcode PluginSpaceBulkUpdateItem}`[]` | Spaces to update |\n */\nexport const PluginSpaceBulkUpdateArgs = z.object({\n items: z.array(PluginSpaceBulkUpdateItem),\n})\n\nexport type PluginSpaceBulkUpdateArgs = z.infer<typeof PluginSpaceBulkUpdateArgs>\n\n/**\n * Result of {@linkcode PluginSpaceApi.bulkUpdate}.\n *\n * Echoes one {@linkcode PluginSpaceUpdateResult} per item, in input order —\n * the same per-space shape returned by {@linkcode PluginSpaceApi.update}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaces` | {@linkcode PluginSpaceUpdateResult}`[]` | Per-item updated values, in input order |\n */\nexport const PluginSpaceBulkUpdateResult = z.object({\n spaces: z.array(PluginSpaceUpdateResult),\n})\n\nexport type PluginSpaceBulkUpdateResult = z.infer<\n typeof PluginSpaceBulkUpdateResult\n>\n\n/**\n * Arguments for {@linkcode PluginSpaceApi.bulkDelete}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceIds` | `string[]` | The space IDs to delete |\n */\nexport const PluginSpaceBulkDeleteArgs = z.object({\n spaceIds: z.array(z.string()),\n})\n\nexport type PluginSpaceBulkDeleteArgs = z.infer<typeof PluginSpaceBulkDeleteArgs>\n\n/**\n * Result of {@linkcode PluginSpaceApi.bulkDelete}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `deletedSpaceIds` | `string[]` | The space IDs that were removed |\n */\nexport const PluginSpaceBulkDeleteResult = z.object({\n deletedSpaceIds: z.array(z.string()),\n})\n\nexport type PluginSpaceBulkDeleteResult = z.infer<\n typeof PluginSpaceBulkDeleteResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Story (floor/storey) management.\n *\n * A story represents a building floor in the Snaptrude project. Stories\n * are identified by their integer **story value** (e.g. `1` for ground\n * floor, `2` for first floor, `-1` for a basement).\n *\n * All methods are **host API calls** that return Promises and support\n * undo/redo via Snaptrude's command system.\n *\n * Accessed via `snaptrude.entity.story`.\n */\nexport abstract class PluginStoryApi {\n constructor() {}\n\n /**\n * Get properties of a story by its storey number.\n *\n * Only the properties listed in {@linkcode PluginStoryGetArgs.properties args.properties}\n * are returned — unlisted properties will be `undefined` in the result.\n *\n * @param args - An object containing:\n * - {@linkcode PluginStoryGetArgs.storyValue args.storyValue} — Integer storey number\n * (e.g. `1` for ground floor, `2` for first floor, `-1` for basement)\n * - {@linkcode PluginStoryGetArgs.properties args.properties} — Array of property names\n * to retrieve. See {@linkcode PluginStoryGetProperty} for available values.\n * @returns A partial {@linkcode PluginStoryGetResult} containing only the requested properties\n * @throws If the story with the given value does not exist\n *\n * # Example\n * ```ts\n * const info = await snaptrude.entity.story.get({\n * storyValue: 1,\n * properties: [\"height\", \"name\", \"spacesCount\"],\n * })\n * console.log(info.name, info.height, info.spacesCount)\n * ```\n */\n public abstract get({\n storyValue,\n properties,\n }: PluginStoryGetArgs): PluginApiReturn<PluginStoryGetResult>\n\n /**\n * Get all stories in the current project.\n *\n * Returns basic identification data for every storey. Stories are sorted\n * from **top to bottom** (highest story value first).\n *\n * @returns A {@linkcode PluginStoryGetAllResult} with a `stories` array,\n * each entry containing `value`, `id`, and `name`\n *\n * # Example\n * ```ts\n * const { stories } = await snaptrude.entity.story.getAll()\n * for (const s of stories) {\n * console.log(`Story ${s.value}: ${s.name} (id: ${s.id})`)\n * }\n * ```\n */\n public abstract getAll(): PluginApiReturn<PluginStoryGetAllResult>\n\n /**\n * Create a new story (floor) in the project.\n *\n * The new story is inserted at the position specified by\n * {@linkcode PluginStoryCreateArgs.storyValue args.storyValue}. This\n * operation is undoable.\n *\n * @param args - An object containing:\n * - {@linkcode PluginStoryCreateArgs.storyValue args.storyValue} — Integer storey number\n * to create (e.g. `3` to add a third floor)\n * - {@linkcode PluginStoryCreateArgs.height args.height} — Optional height in Babylon\n * units. If omitted, the project's default storey height is used.\n * @returns A {@linkcode PluginStoryCreateResult} with `storyId` and `storyValue`\n * @throws If a story with the given value already exists or creation fails\n *\n * # Example\n * ```ts\n * // Create a new third floor with custom height\n * const { storyId } = await snaptrude.entity.story.create({\n * storyValue: 3,\n * height: 4.5,\n * })\n * ```\n */\n public abstract create({\n storyValue,\n height,\n }: PluginStoryCreateArgs): PluginApiReturn<PluginStoryCreateResult>\n\n /**\n * Update a story's height.\n *\n * Changes the floor-to-floor height of the specified story. This\n * operation is undoable.\n *\n * @param args - An object containing:\n * - {@linkcode PluginStoryUpdateArgs.storyValue args.storyValue} — Integer storey number\n * identifying the story to update\n * - {@linkcode PluginStoryUpdateArgs.height args.height} — New height value in Babylon\n * units\n * @returns A {@linkcode PluginStoryUpdateResult} with the updated `storyValue` and `height`\n * @throws If the story does not exist or the update fails\n *\n * # Example\n * ```ts\n * // Set ground floor height to 5 Babylon units\n * const result = await snaptrude.entity.story.update({\n * storyValue: 1,\n * height: 5,\n * })\n * ```\n */\n public abstract update({\n storyValue,\n height,\n }: PluginStoryUpdateArgs): PluginApiReturn<PluginStoryUpdateResult>\n}\n\n/**\n * Available properties that can be queried on a story.\n *\n * | Value | Type | Description |\n * |---|---|---|\n * | `\"value\"` | `number` | The integer storey number |\n * | `\"id\"` | `string` | Unique story identifier |\n * | `\"name\"` | `string` | Display name of the story |\n * | `\"height\"` | `number` | Floor-to-floor height in Babylon units |\n * | `\"base\"` | `number` | Base elevation in Babylon units |\n * | `\"hidden\"` | `boolean` | Whether the story is hidden in the viewport |\n * | `\"spacesCount\"` | `number` | Number of spaces on this story |\n * | `\"totalArea\"` | `number` | Total floor area of this story |\n */\nexport const PluginStoryGetProperty = z.enum([\n \"value\",\n \"id\",\n \"name\",\n \"height\",\n \"base\",\n \"hidden\",\n \"spacesCount\",\n \"totalArea\",\n])\n\n/**\n * Arguments for {@linkcode PluginStoryApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storyValue` | `number` (int) | The storey number to query |\n * | `properties` | {@linkcode PluginStoryGetProperty}`[]` | Properties to retrieve |\n */\nexport const PluginStoryGetArgs = z.object({\n storyValue: z.number().int(),\n properties: z.array(PluginStoryGetProperty),\n})\n\nexport type PluginStoryGetArgs = z.infer<typeof PluginStoryGetArgs>\n\n/**\n * Result of {@linkcode PluginStoryApi.get}.\n *\n * A partial object — only the properties that were requested in\n * {@linkcode PluginStoryGetArgs.properties} will be present.\n */\nexport const PluginStoryGetResult = z\n .object({\n value: z.number(),\n id: z.string(),\n name: z.string(),\n height: z.number(),\n base: z.number(),\n hidden: z.boolean(),\n spacesCount: z.number(),\n totalArea: z.number(),\n })\n .partial()\n\nexport type PluginStoryGetResult = z.infer<typeof PluginStoryGetResult>\n\n/**\n * Result of {@linkcode PluginStoryApi.getAll}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `stories` | `Array<{ value, id, name }>` | All stories, sorted top to bottom |\n */\nexport const PluginStoryGetAllResult = z.object({\n stories: z.array(\n z.object({\n value: z.number(),\n id: z.string(),\n name: z.string(),\n })\n ),\n})\n\nexport type PluginStoryGetAllResult = z.infer<typeof PluginStoryGetAllResult>\n\n/**\n * Arguments for {@linkcode PluginStoryApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storyValue` | `number` (int) | The storey number for the new story |\n * | `height` | `number?` | Optional height in Babylon units |\n */\nexport const PluginStoryCreateArgs = z.object({\n storyValue: z.number().int(),\n height: z.number().optional(),\n})\n\nexport type PluginStoryCreateArgs = z.infer<typeof PluginStoryCreateArgs>\n\n/**\n * Result of {@linkcode PluginStoryApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storyId` | `string` | Unique ID of the created story |\n * | `storyValue` | `number` | The storey number of the created story |\n */\nexport const PluginStoryCreateResult = z.object({\n storyId: z.string(),\n storyValue: z.number(),\n})\n\nexport type PluginStoryCreateResult = z.infer<typeof PluginStoryCreateResult>\n\n/**\n * Arguments for {@linkcode PluginStoryApi.update}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storyValue` | `number` (int) | Storey number of the story to update |\n * | `height` | `number` | New height in Babylon units |\n */\nexport const PluginStoryUpdateArgs = z.object({\n storyValue: z.number().int(),\n height: z.number(),\n})\n\nexport type PluginStoryUpdateArgs = z.infer<typeof PluginStoryUpdateArgs>\n\n/**\n * Result of {@linkcode PluginStoryApi.update}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storyValue` | `number` | The storey number of the updated story |\n * | `height` | `number` | The new height after the update |\n */\nexport const PluginStoryUpdateResult = z.object({\n storyValue: z.number(),\n height: z.number(),\n})\n\nexport type PluginStoryUpdateResult = z.infer<typeof PluginStoryUpdateResult>\n","import { PluginBuildableEnvelopeApi } from \"./buildableEnvelope\"\nimport { PluginDepartmentApi } from \"./department\"\nimport { PluginReferenceLineApi } from \"./referenceLine\"\nimport { PluginSpaceApi } from \"./space\"\nimport { PluginStoryApi } from \"./story\"\n\n/**\n * CRUD operations on Snaptrude building entities.\n *\n * - {@linkcode PluginEntityApi.space} — Create, query, and delete spaces (rooms/masses)\n * - {@linkcode PluginEntityApi.story} — Create, query, and update stories (floors)\n * - {@linkcode PluginEntityApi.referenceLine} — Create, query, and delete reference lines\n * - {@linkcode PluginEntityApi.department} — Create and query departments\n * - {@linkcode PluginEntityApi.buildableEnvelope} — Create or update parametric buildable envelopes\n */\nexport abstract class PluginEntityApi {\n /** Space (room/mass) operations. See {@linkcode PluginSpaceApi}. */\n public abstract space: PluginSpaceApi\n /** Story (floor/storey) operations. See {@linkcode PluginStoryApi}. */\n public abstract story: PluginStoryApi\n /** Reference line operations. See {@linkcode PluginReferenceLineApi}. */\n public abstract referenceLine: PluginReferenceLineApi\n /** Department operations. See {@linkcode PluginDepartmentApi}. */\n public abstract department: PluginDepartmentApi\n /** Buildable Envelope operations. See {@linkcode PluginBuildableEnvelopeApi}. */\n public abstract buildableEnvelope: PluginBuildableEnvelopeApi\n\n constructor() {}\n}\n\nexport * from \"./buildableEnvelope\"\nexport * from \"./department\"\nexport * from \"./referenceLine\"\nexport * from \"./space\"\nexport * from \"./story\"\n","import * as z from \"zod\"\nimport type { ComponentId } from \"../../types\"\nimport { PVec3 } from \"../core/math/vec3\"\n\n/**\n * Copy mode for `snaptrude.tools.copy`.\n *\n * | Value | Description |\n * |---|---|\n * | `\"instance\"` | Create instanced copies where possible |\n * | `\"unique\"` | Create independent geometry copies |\n */\nexport const PluginCopyMode = z.enum([\"instance\", \"unique\"])\n\nexport type PluginCopyMode = z.infer<typeof PluginCopyMode>\n\n/**\n * Arguments for `snaptrude.tools.copy`.\n *\n * Creates one or more copies for each component in `componentIds`. Copy `i` is\n * offset by `displacement * i`, where `i` starts at `1`. Source positions are\n * preserved. In `\"instance\"` mode, a unique source mesh can be replaced by an\n * instance at the same position so the source and copied objects remain in the\n * same instance family. The created copy stack becomes the active editor\n * selection, matching the native paste workflow.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `componentIds` | `string[]` | Component IDs to copy |\n * | `displacement` | {@linkcode PVec3} | Offset applied to each copy in Babylon units |\n * | `count` | `number` | Number of copies per component. Defaults to `1` |\n * | `copyMode` | {@linkcode PluginCopyMode} | `\"instance\"` or `\"unique\"`. Defaults to `\"instance\"` |\n */\nexport const PluginCopyArgs = z.object({\n componentIds: z.array(z.string()).min(1),\n displacement: PVec3,\n count: z.number().int().positive().optional(),\n copyMode: PluginCopyMode.optional(),\n})\n\nexport type PluginCopyArgs = z.infer<typeof PluginCopyArgs>\n\n/**\n * Result of `snaptrude.tools.copy`.\n *\n * Returned IDs are Snaptrude component IDs for the newly created copies, not\n * Babylon mesh IDs.\n */\nexport const PluginCopyResult = z.object({\n copiedIds: z.array(z.string()),\n})\n\nexport type PluginCopyResult = {\n copiedIds: ComponentId[]\n}\n","import * as z from \"zod\"\nimport type { ComponentId } from \"../../types\"\nimport { PVec3 } from \"../core/math/vec3\"\n\n/**\n * Arguments for `snaptrude.tools.offset`.\n *\n * Runs Snaptrude's offset/split operation on the top profile of a scene\n * component. A positive distance offsets outward from the selected profile;\n * a negative distance offsets inward. If `profilePickPoint` is omitted, the\n * outer top profile is used. If `profilePickPoint` is provided, the nearest top\n * contour profile to that point is used, matching the interactive offset tool's\n * pick behavior.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `componentId` | `string` | Component ID to offset |\n * | `distance` | `number` | Signed offset distance in Snaptrude units |\n * | `profilePickPoint` | {@linkcode PVec3} | Optional point used to choose a top contour profile |\n */\nexport const PluginOffsetArgs = z.object({\n componentId: z.string().min(1),\n distance: z.number(),\n profilePickPoint: PVec3.optional(),\n})\n\nexport type PluginOffsetArgs = z.infer<typeof PluginOffsetArgs>\n\n/**\n * Result of `snaptrude.tools.offset`.\n *\n * `createdIds` are the components created by the offset operation. `deletedIds`\n * are components removed by split-style offsets.\n */\nexport const PluginOffsetResult = z.object({\n createdIds: z.array(z.string()),\n deletedIds: z.array(z.string()),\n})\n\nexport type PluginOffsetResult = {\n createdIds: ComponentId[]\n deletedIds: ComponentId[]\n}\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Query the current user selection in the Snaptrude editor.\n *\n * Accessed via `snaptrude.tools.selection`.\n */\nexport abstract class PluginSelectionApi {\n constructor() {}\n\n /**\n * Get the IDs of all currently selected components.\n *\n * Returns the component IDs from the editor's active selection stack.\n * If nothing is selected, returns an empty array.\n *\n * The returned IDs can be used with {@linkcode PluginTransformApi.move},\n * {@linkcode PluginTransformApi.rotate}, or entity query methods like\n * {@linkcode PluginSpaceApi.get}.\n *\n * @returns A {@linkcode PluginSelectionGetResult} with a `selected` array\n * of component ID strings\n *\n * # Example\n * ```ts\n * const { selected } = await snaptrude.tools.selection.get()\n * if (selected.length > 0) {\n * // Move selected components 5 units along X\n * await snaptrude.tools.transform.move({\n * componentIds: selected,\n * displacement: snaptrude.core.math.vec3.new(5, 0, 0),\n * })\n * }\n * ```\n */\n public abstract get(): PluginApiReturn<PluginSelectionGetResult>\n}\n\n/**\n * Result of {@linkcode PluginSelectionApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `selected` | `string[]` | Component IDs of the current selection |\n */\nexport const PluginSelectionGetResult = z.object({\n selected: z.array(z.string()),\n})\n\nexport type PluginSelectionGetResult = z.infer<typeof PluginSelectionGetResult>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\nimport { PVec3 } from \"../core/math/vec3\"\n\n/**\n * Transform operations — move and rotate scene components.\n *\n * All transform methods accept an array of component IDs and apply the\n * transformation to each. Operations are recorded in Snaptrude's\n * command system for undo/redo support.\n *\n * Accessed via `snaptrude.tools.transform`.\n */\nexport abstract class PluginTransformApi {\n constructor() {}\n\n /**\n * Translate components by a displacement vector.\n *\n * Each component's position is offset by the given\n * {@linkcode PluginMoveArgs.displacement displacement} vector.\n * This operation is undoable.\n *\n * @param args - An object containing:\n * - {@linkcode PluginMoveArgs.componentIds args.componentIds} — Array of component\n * ID strings to move\n * - {@linkcode PluginMoveArgs.displacement args.displacement} — Translation vector\n * as a {@linkcode PVec3} in Babylon units\n * @throws If any component ID is not found in the scene\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n *\n * // Move a space 10 units along the X axis\n * await snaptrude.tools.transform.move({\n * componentIds: [\"some-space-id\"],\n * displacement: vec3.new(10, 0, 0),\n * })\n * ```\n */\n public abstract move({\n componentIds,\n displacement,\n }: PluginMoveArgs): PluginApiReturn<void>\n\n /**\n * Rotate components around an axis through a pivot point.\n *\n * Each component is rotated by {@linkcode PluginRotateArgs.angle angle}\n * radians around the {@linkcode PluginRotateArgs.axis axis} vector,\n * pivoting about the {@linkcode PluginRotateArgs.pivot pivot} point.\n * This operation is undoable.\n *\n * @param args - An object containing:\n * - {@linkcode PluginRotateArgs.componentIds args.componentIds} — Array of component\n * ID strings to rotate\n * - {@linkcode PluginRotateArgs.angle args.angle} — Rotation angle in **radians**\n * - {@linkcode PluginRotateArgs.axis args.axis} — Rotation axis as a {@linkcode PVec3}\n * - {@linkcode PluginRotateArgs.pivot args.pivot} — Pivot point as a {@linkcode PVec3}\n * in Babylon units\n * @throws If any component ID is not found in the scene\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n *\n * // Rotate a space 45° around the Y axis at the origin\n * await snaptrude.tools.transform.rotate({\n * componentIds: [\"some-space-id\"],\n * angle: Math.PI / 4,\n * axis: vec3.new(0, 1, 0),\n * pivot: vec3.new(0, 0, 0),\n * })\n * ```\n */\n public abstract rotate({\n componentIds,\n angle,\n axis,\n pivot,\n }: PluginRotateArgs): PluginApiReturn<void>\n}\n\n/**\n * Arguments for {@linkcode PluginTransformApi.move}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `componentIds` | `string[]` | Component IDs to move |\n * | `displacement` | {@linkcode PVec3} | Translation vector in Babylon units |\n */\nexport const PluginMoveArgs = z.object({\n componentIds: z.array(z.string()),\n displacement: PVec3,\n})\n\nexport type PluginMoveArgs = z.infer<typeof PluginMoveArgs>\n\n/**\n * Arguments for {@linkcode PluginTransformApi.rotate}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `componentIds` | `string[]` | Component IDs to rotate |\n * | `angle` | `number` | Rotation angle in radians |\n * | `axis` | {@linkcode PVec3} | Rotation axis direction |\n * | `pivot` | {@linkcode PVec3} | Pivot point in Babylon units |\n */\nexport const PluginRotateArgs = z.object({\n componentIds: z.array(z.string()),\n angle: z.number(),\n axis: PVec3,\n pivot: PVec3,\n})\n\nexport type PluginRotateArgs = z.infer<typeof PluginRotateArgs>\n","import { PluginSelectionApi } from \"./selection\"\nimport { PluginTransformApi } from \"./transform\"\nimport type { PluginApiReturn } from \"../../types\"\nimport type { PluginCopyArgs, PluginCopyResult } from \"./copy\"\nimport type { PluginOffsetArgs, PluginOffsetResult } from \"./offset\"\n\n/**\n * Snaptrude editor tools for querying and manipulating scene components.\n *\n * - {@linkcode PluginToolsApi.selection} — Query the current user selection\n * - {@linkcode PluginToolsApi.transform} — Move and rotate components\n * - {@linkcode PluginToolsApi.copy} — Copy components\n * - {@linkcode PluginToolsApi.offset} — Offset or split component profiles\n */\nexport abstract class PluginToolsApi {\n /** Query the current selection. See {@linkcode PluginSelectionApi}. */\n public abstract selection: PluginSelectionApi\n /** Move and rotate components. See {@linkcode PluginTransformApi}. */\n public abstract transform: PluginTransformApi\n\n /** Copy components by ID. See {@linkcode PluginCopyArgs}. */\n public abstract copy(args: PluginCopyArgs): PluginApiReturn<PluginCopyResult>\n\n /** Offset or split a component profile. See {@linkcode PluginOffsetArgs}. */\n public abstract offset(\n args: PluginOffsetArgs,\n ): PluginApiReturn<PluginOffsetResult>\n\n constructor() {}\n}\n\nexport * from \"./copy\"\nexport * from \"./offset\"\nexport * from \"./selection\"\nexport * from \"./transform\"\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Unit conversion between real-world units and Snaptrude's internal\n * (Babylon) coordinate system.\n *\n * Snaptrude uses an internal unit system (Babylon units) for all\n * coordinates and dimensions. Use these methods to convert between\n * real-world measurements and Babylon units.\n *\n * Accessed via `snaptrude.units`.\n */\nexport abstract class PluginUnitsApi {\n constructor() {}\n\n /**\n * Convert a value from a real-world unit to Snaptrude's internal (Babylon) units.\n *\n * Use this when you have a measurement in real-world units (e.g. meters, feet)\n * and need to convert it to the coordinate system used by Snaptrude internally.\n *\n * @param args - An object containing:\n * - {@linkcode PluginUnitsConvertFromArgs.unit args.unit} — The source unit\n * to convert from. See {@linkcode PUnitType} for supported values.\n * - {@linkcode PluginUnitsConvertFromArgs.value args.value} — The numeric\n * value in the source unit\n * - {@linkcode PluginUnitsConvertFromArgs.degree args.degree} — (Optional)\n * Degree of the unit: 1 for length, 2 for area, 3 for volume. Defaults to 1\n * @returns A {@linkcode PluginUnitsConvertFromResult} containing the converted\n * `value` in Babylon units\n *\n * # Example\n * ```ts\n * // Convert 5 meters to Babylon units for use in API calls\n * const result = await snaptrude.units.convertFrom({ unit: \"meters\", value: 5 })\n * const { spaceId } = await snaptrude.entity.space.createRectangular({\n * position: snaptrude.core.math.vec3.new(0, 0, 0),\n * dimensions: { width: result.value, height: result.value, depth: result.value },\n * })\n * ```\n */\n public abstract convertFrom(\n args: PluginUnitsConvertFromArgs,\n ): PluginApiReturn<PluginUnitsConvertFromResult>\n\n /**\n * Convert a value from Snaptrude's internal (Babylon) units to a real-world unit.\n *\n * Use this when you have a value in Snaptrude's internal coordinate system\n * and need to express it in real-world units (e.g. meters, feet).\n *\n * @param args - An object containing:\n * - {@linkcode PluginUnitsConvertToArgs.unit args.unit} — The target unit\n * to convert to. See {@linkcode PUnitType} for supported values.\n * - {@linkcode PluginUnitsConvertToArgs.value args.value} — The numeric\n * value in Babylon units\n * - {@linkcode PluginUnitsConvertToArgs.degree args.degree} — (Optional)\n * Degree of the unit: 1 for length, 2 for area, 3 for volume. Defaults to 1\n * @returns A {@linkcode PluginUnitsConvertToResult} containing the converted\n * `value` in the target unit\n *\n * # Example\n * ```ts\n * // Get a space's area in square meters\n * const info = await snaptrude.entity.space.get({\n * spaceId: \"some-id\",\n * properties: [\"area\"],\n * })\n * const areaInMeters = await snaptrude.units.convertTo({\n * unit: \"meters\",\n * value: info.area!,\n * degree: 2,\n * })\n * ```\n */\n public abstract convertTo(\n args: PluginUnitsConvertToArgs,\n ): PluginApiReturn<PluginUnitsConvertToResult>\n}\n\n/**\n * Supported unit types for conversion.\n *\n * - `meters` — Metric meters\n * - `feet-inches` — Imperial feet (1 foot = 12 inches)\n * - `inches` — Imperial inches\n * - `centimeters` — Metric centimeters\n * - `millimeters` — Metric millimeters\n * - `kilometers` — Metric kilometers\n * - `miles` — Imperial miles\n */\nexport const PUnitType = z.enum([\n \"meters\",\n \"feet-inches\",\n \"inches\",\n \"centimeters\",\n \"millimeters\",\n \"kilometers\",\n \"miles\",\n])\n\nexport type PUnitType = z.infer<typeof PUnitType>\n\n/**\n * Arguments for {@linkcode PluginUnitsApi.convertFrom}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `unit` | {@linkcode PUnitType} | Source real-world unit |\n * | `value` | `number` | Numeric value in the source unit |\n * | `degree` | `1 \\| 2 \\| 3` | (Optional) Degree of the unit (e.g. 1 for length, 2 for area, 3 for volume). Defaults to 1 |\n */\nexport const PluginUnitsConvertFromArgs = z.object({\n unit: PUnitType,\n value: z.number(),\n degree: z.number().int().min(1).max(3).optional(),\n})\n\nexport type PluginUnitsConvertFromArgs = z.infer<typeof PluginUnitsConvertFromArgs>\n\n/**\n * Result of {@linkcode PluginUnitsApi.convertFrom}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `value` | `number` | The converted value in Babylon units |\n */\nexport const PluginUnitsConvertFromResult = z.object({\n value: z.number(),\n})\n\nexport type PluginUnitsConvertFromResult = z.infer<typeof PluginUnitsConvertFromResult>\n\n/**\n * Arguments for {@linkcode PluginUnitsApi.convertTo}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `unit` | {@linkcode PUnitType} | Target real-world unit |\n * | `value` | `number` | Numeric value in Babylon units |\n * | `degree` | `1 \\| 2 \\| 3` | (Optional) Degree of the unit (e.g. 1 for length, 2 for area, 3 for volume). Defaults to 1 |\n */\nexport const PluginUnitsConvertToArgs = z.object({\n unit: PUnitType,\n value: z.number(),\n degree: z.number().int().min(1).max(3).optional(),\n})\n\nexport type PluginUnitsConvertToArgs = z.infer<typeof PluginUnitsConvertToArgs>\n\n/**\n * Result of {@linkcode PluginUnitsApi.convertTo}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `value` | `number` | The converted value in the target unit |\n */\nexport const PluginUnitsConvertToResult = z.object({\n value: z.number(),\n})\n\nexport type PluginUnitsConvertToResult = z.infer<typeof PluginUnitsConvertToResult>\n","import { PluginCoreApi } from \"./core\"\nimport { PluginEntityApi } from \"./entity\"\nimport { PluginToolsApi } from \"./tools\"\nimport { PluginUnitsApi } from \"./units\"\nimport { PluginDocumentationApi } from \"./documentation\"\n\n/**\n * Root API surface for Snaptrude plugins.\n *\n * Access all plugin capabilities through the namespaced properties:\n *\n * - {@linkcode PluginApi.core} — Math and geometry primitives\n * - {@linkcode PluginApi.entity} — CRUD operations on Snaptrude entities (spaces, stories)\n * - {@linkcode PluginApi.tools} — Copy, offset, selection, and transform tools\n * - {@linkcode PluginApi.units} — Unit conversion utilities\n * - {@linkcode PluginApi.documentation} — Present documentation APIs\n */\nexport abstract class PluginApi {\n /** Core math and geometry primitives. See {@linkcode PluginCoreApi}. */\n public abstract core: PluginCoreApi\n /** Copy, offset, selection, and transform tools. See {@linkcode PluginToolsApi}. */\n public abstract tools: PluginToolsApi\n /** CRUD operations on Snaptrude entities. See {@linkcode PluginEntityApi}. */\n public abstract entity: PluginEntityApi\n /** Unit conversion utilities. See {@linkcode PluginUnitsApi}. */\n public abstract units: PluginUnitsApi\n /** Present documentation APIs. See {@linkcode PluginDocumentationApi}. */\n public abstract documentation: PluginDocumentationApi\n\n constructor() {}\n}\n\nexport * from \"./core\"\nexport * from \"./documentation\"\nexport * from \"./entity\"\nexport * from \"./tools\"\nexport * from \"./units\"\n"],"mappings":";AAAA,YAAY,OAAO;AAUZ,IAAe,gBAAf,MAA6B;AAAA,EAClC,cAAc;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBf,IAAI,GAAW,GAAWA,KAAkB;AAC1C,WAAO,EAAE,GAAG,GAAG,GAAAA,IAAE;AAAA,EACnB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,IAAI,GAAU,GAAiB;AAC7B,WAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,EAAE;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,SAAS,GAAU,GAAiB;AAClC,WAAO,EAAE,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,GAAG,GAAG,EAAE,IAAI,EAAE,EAAE;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,MAAM,GAAU,QAAuB;AACrC,WAAO,EAAE,GAAG,EAAE,IAAI,QAAQ,GAAG,EAAE,IAAI,QAAQ,GAAG,EAAE,IAAI,OAAO;AAAA,EAC7D;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,IAAI,GAAU,GAAkB;AAC9B,WAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAaA,MAAM,GAAU,GAAiB;AAC/B,WAAO;AAAA,MACL,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAAA,MACvB,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAAA,MACvB,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,GAAkB;AACvB,WAAO,KAAK,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,cAAc,GAAkB;AAC9B,WAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAAA,EACzC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,UAAU,GAAiB;AACzB,UAAM,MAAM,KAAK,OAAO,CAAC;AACzB,QAAI,QAAQ,EAAG,QAAO,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AACzC,WAAO,EAAE,GAAG,EAAE,IAAI,KAAK,GAAG,EAAE,IAAI,KAAK,GAAG,EAAE,IAAI,IAAI;AAAA,EACpD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EASA,SAAS,GAAU,GAAkB;AACnC,WAAO,KAAK,OAAO,KAAK,SAAS,GAAG,CAAC,CAAC;AAAA,EACxC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,KAAK,GAAU,GAAU,GAAkB;AACzC,WAAO;AAAA,MACL,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK;AAAA,MACvB,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK;AAAA,MACvB,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,GAAiB;AACtB,WAAO,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,EAAE;AAAA,EACrC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,GAAU,GAAmB;AAClC,WAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,aAAa,GAAU,GAAU,UAAkB,MAAe;AAChE,WACE,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,WACtB,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,WACtB,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI;AAAA,EAE1B;AACF;AAQO,IAAM,QAAU,SAAO;AAAA,EAC5B,GAAK,SAAO;AAAA,EACZ,GAAK,SAAO;AAAA,EACZ,GAAK,SAAO;AACd,CAAC;;;ACnND,YAAYC,QAAO;AAYZ,IAAe,gBAAf,MAA6B;AAAA,EAClC,cAAc;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAcf,IAAI,GAAW,GAAWA,KAAW,GAAkB;AACrD,WAAO,EAAE,GAAG,GAAG,GAAAA,KAAG,EAAE;AAAA,EACtB;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAOA,WAAkB;AAChB,WAAO,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAAA,EAClC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAgBA,cAAc,MAAa,OAAsB;AAC/C,UAAM,YAAY,QAAQ;AAC1B,UAAM,IAAI,KAAK,IAAI,SAAS;AAC5B,UAAM,MAAM,KAAK,KAAK,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,IAAI,KAAK,CAAC;AACzE,QAAI,QAAQ,EAAG,QAAO,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAC/C,WAAO;AAAA,MACL,GAAI,KAAK,IAAI,MAAO;AAAA,MACpB,GAAI,KAAK,IAAI,MAAO;AAAA,MACpB,GAAI,KAAK,IAAI,MAAO;AAAA,MACpB,GAAG,KAAK,IAAI,SAAS;AAAA,IACvB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,UAAU,GAAW,GAAWA,KAAkB;AAChD,UAAM,KAAK,KAAK,IAAI,IAAI,CAAC;AACzB,UAAM,KAAK,KAAK,IAAI,IAAI,CAAC;AACzB,UAAM,KAAK,KAAK,IAAI,IAAI,CAAC;AACzB,UAAM,KAAK,KAAK,IAAI,IAAI,CAAC;AACzB,UAAM,KAAK,KAAK,IAAIA,MAAI,CAAC;AACzB,UAAM,KAAK,KAAK,IAAIA,MAAI,CAAC;AACzB,WAAO;AAAA,MACL,GAAG,KAAK,KAAK,KAAK,KAAK,KAAK;AAAA,MAC5B,GAAG,KAAK,KAAK,KAAK,KAAK,KAAK;AAAA,MAC5B,GAAG,KAAK,KAAK,KAAK,KAAK,KAAK;AAAA,MAC5B,GAAG,KAAK,KAAK,KAAK,KAAK,KAAK;AAAA,IAC9B;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,SAAS,GAAU,GAAiB;AAClC,WAAO;AAAA,MACL,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAAA,MAC/C,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAAA,MAC/C,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAAA,MAC/C,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAAA,IACjD;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,UAAU,GAAiB;AACzB,WAAO,EAAE,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,CAAC,EAAE,GAAG,GAAG,EAAE,EAAE;AAAA,EAC7C;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,OAAO,GAAkB;AACvB,WAAO,KAAK,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAQA,UAAU,GAAiB;AACzB,UAAM,MAAM,KAAK,OAAO,CAAC;AACzB,QAAI,QAAQ,EAAG,QAAO,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AAC/C,WAAO,EAAE,GAAG,EAAE,IAAI,KAAK,GAAG,EAAE,IAAI,KAAK,GAAG,EAAE,IAAI,KAAK,GAAG,EAAE,IAAI,IAAI;AAAA,EAClE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,QAAQ,GAAiB;AACvB,UAAM,QAAQ,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAC1D,QAAI,UAAU,EAAG,QAAO,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE;AACjD,WAAO,EAAE,GAAG,CAAC,EAAE,IAAI,OAAO,GAAG,CAAC,EAAE,IAAI,OAAO,GAAG,CAAC,EAAE,IAAI,OAAO,GAAG,EAAE,IAAI,MAAM;AAAA,EAC7E;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAmBA,WAAW,GAAU,GAAiB;AACpC,UAAM,KAAY,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,GAAG,GAAG,EAAE,GAAG,GAAG,EAAE;AACjD,UAAM,OAAO,KAAK,UAAU,CAAC;AAC7B,UAAM,SAAS,KAAK,SAAS,KAAK,SAAS,GAAG,EAAE,GAAG,IAAI;AACvD,WAAO,EAAE,GAAG,OAAO,GAAG,GAAG,OAAO,GAAG,GAAG,OAAO,EAAE;AAAA,EACjD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,YAAY,GAA0C;AACpD,UAAM,KAAK,KAAK,UAAU,CAAC;AAC3B,UAAM,QAAQ,IAAI,KAAK,KAAK,KAAK,IAAI,GAAG,KAAK,IAAI,IAAI,GAAG,CAAC,CAAC,CAAC;AAC3D,UAAM,IAAI,KAAK,IAAI,QAAQ,CAAC;AAC5B,QAAI,IAAI,MAAM;AACZ,aAAO,EAAE,MAAM,EAAE,GAAG,GAAG,GAAG,GAAG,GAAG,EAAE,GAAG,OAAO,EAAE;AAAA,IAChD;AACA,WAAO;AAAA,MACL,MAAM,EAAE,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,IAAI,GAAG,GAAG,GAAG,IAAI,EAAE;AAAA,MAC9C;AAAA,IACF;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,MAAM,GAAU,GAAU,GAAkB;AAC1C,QAAI,UAAU,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAC1D,QAAI,KAAK,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,EAAE,GAAG,KAAK,EAAE;AACzC,QAAI,UAAU,GAAG;AACf,gBAAU,CAAC;AACX,WAAK,CAAC;AAAI,WAAK,CAAC;AAAI,WAAK,CAAC;AAAI,WAAK,CAAC;AAAA,IACtC;AACA,QAAI,WAAW,GAAK;AAClB,aAAO,EAAE,GAAG,EAAE,GAAG,GAAG,EAAE,GAAG,GAAG,EAAE,GAAG,GAAG,EAAE,EAAE;AAAA,IAC1C;AACA,UAAM,YAAY,KAAK,KAAK,OAAO;AACnC,UAAM,UAAU,KAAK,IAAI,SAAS;AAClC,UAAM,SAAS,KAAK,KAAK,IAAI,KAAK,SAAS,IAAI;AAC/C,UAAM,SAAS,KAAK,IAAI,IAAI,SAAS,IAAI;AACzC,WAAO;AAAA,MACL,GAAG,EAAE,IAAI,SAAS,KAAK;AAAA,MACvB,GAAG,EAAE,IAAI,SAAS,KAAK;AAAA,MACvB,GAAG,EAAE,IAAI,SAAS,KAAK;AAAA,MACvB,GAAG,EAAE,IAAI,SAAS,KAAK;AAAA,IACzB;AAAA,EACF;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAYA,IAAI,GAAU,GAAkB;AAC9B,WAAO,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE;AAAA,EACrD;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWA,OAAO,GAAU,GAAmB;AAClC,WAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE;AAAA,EAChE;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAUA,aAAa,GAAU,GAAU,UAAkB,MAAe;AAChE,WACE,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,WACtB,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,WACtB,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI,WACtB,KAAK,IAAI,EAAE,IAAI,EAAE,CAAC,IAAI;AAAA,EAE1B;AACF;AAQO,IAAM,QAAU,UAAO;AAAA,EAC5B,GAAK,UAAO;AAAA,EACZ,GAAK,UAAO;AAAA,EACZ,GAAK,UAAO;AAAA,EACZ,GAAK,UAAO;AACd,CAAC;;;AC3RM,IAAe,gBAAf,MAA6B;AAAA,EAMlC,cAAc;AAAA,EAAC;AACjB;;;AChBA,YAAYC,QAAO;AAYZ,IAAe,gBAAf,MAA6B;AAAA,EAClC,cAAc;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAiBf,IAAI,YAAmB,UAAwB;AAC7C,WAAO,EAAE,WAAW,QAAQ,YAAY,SAAS;AAAA,EACnD;AACF;AAaO,IAAM,QAAU,UAAO;AAAA,EAC5B,WAAa,WAAQ,MAAM;AAAA,EAC3B,YAAY;AAAA,EACZ,UAAU;AACZ,CAAC;;;AClDD,YAAYC,QAAO;AAYZ,IAAe,eAAf,MAA4B;AAAA,EACjC,cAAc;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EA8Bf,IAAI,YAAmB,UAAiB,aAAoB,MAAmB;AAC7E,WAAO,EAAE,WAAW,OAAO,YAAY,UAAU,aAAa,KAAK;AAAA,EACrE;AACF;AAeO,IAAM,OAAS,UAAO;AAAA,EAC3B,WAAa,WAAQ,KAAK;AAAA,EAC1B,YAAY;AAAA,EACZ,UAAU;AAAA,EACV,aAAa;AAAA,EACb,MAAM;AACR,CAAC;;;ACnED,YAAYC,QAAO;AAYZ,IAAe,iBAAf,MAA8B;AAAA,EACnC,cAAc;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWf,IAAI,OAA6B;AAC/B,WAAO;AAAA,EACT;AACF;AAWO,IAAM,SAAW,sBAAmB,aAAa,CAAC,OAAO,IAAI,CAAC;;;ACtCrE,YAAYC,QAAO;AAeZ,IAAe,mBAAf,MAAgC;AAAA,EACrC,cAAc;AAAA,EAAC;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA;AAAA,EAWf,IAAI,QAA4B;AAC9B,WAAO,EAAE,OAAO;AAAA,EAClB;AAmCF;AASO,IAAM,kCAAoC,UAAO;AAAA,EACtD,QAAU,SAAM,KAAK;AACvB,CAAC;AAcM,IAAM,WAAa,UAAO;AAAA,EAC/B,QAAU,SAAM,MAAM;AACxB,CAAC;;;AC1EM,IAAe,gBAAf,MAA6B;AAAA,EAUlC,cAAc;AAAA,EAAC;AACjB;;;ACnBO,IAAe,gBAAf,MAA6B;AAAA,EAMlC,cAAc;AAAA,EAAC;AACjB;;;AChBA,YAAYC,QAAO;AAGnB,IAAM,gBAAkB,SAAM,CAAG,UAAO,GAAK,UAAO,GAAK,WAAQ,GAAK,QAAK,CAAC,CAAC;AAK7E,IAAM,YAAoC;AAAA,EAAK,MAC3C,SAAM,CAAC,eAAiB,SAAM,SAAS,GAAK,UAAS,UAAO,GAAG,SAAS,CAAC,CAAC;AAC9E;AAEO,IAAM,6BAA+B,QAAK,CAAC,YAAY,KAAK,CAAC;AAK7D,IAAM,gCAAkC,QAAK;AAAA,EAClD;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAKM,IAAM,iCAAmC,QAAK,CAAC,SAAS,OAAO,CAAC;AAKhE,IAAM,qCAAuC,QAAK,CAAC,OAAO,KAAK,CAAC;AAKhE,IAAM,oCAAsC,QAAK;AAAA,EACtD;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAKM,IAAM,+BAAiC,QAAK,CAAC,SAAS,QAAQ,OAAO,CAAC;AAKtE,IAAM,+BAAiC,QAAK;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAKM,IAAM,iCAAmC,QAAK;AAAA,EACnD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAKM,IAAM,mCAAqC,QAAK,CAAC,MAAM,MAAM,IAAI,CAAC;AAKlE,IAAM,+BAAiC,QAAK;AAAA,EACjD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAKM,IAAM,sCAAwC,QAAK;AAAA,EACxD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAKM,IAAM,gCAAkC,UAAO;AAAA,EACpD,GAAK,UAAO,EAAE,OAAO;AAAA,EACrB,GAAK,UAAO,EAAE,OAAO;AAAA,EACrB,GAAK,UAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,GAAK,UAAO,EAAE,OAAO,EAAE,SAAS;AAClC,CAAC;AAKM,IAAM,2BAA6B,UAAO;AAAA,EAC/C,GAAK,UAAO,EAAE,OAAO;AAAA,EACrB,GAAK,UAAO,EAAE,OAAO;AACvB,CAAC;AAGM,IAAM,oCAAsC,UAAO;AAAA,EACxD,MAAQ,UAAO,EAAE,IAAI,CAAC;AAAA,EACtB,GAAK,UAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAChC,GAAK,UAAO,EAAE,OAAO,EAAE,SAAS;AAClC,CAAC;AAKM,IAAM,oCAAsC,UAAO;AAAA,EACxD,gBAAkB,SAAQ,UAAO,CAAC,EAAE,SAAS;AAAA,EAC7C,iBAAmB,SAAM,iCAAiC,EAAE,SAAS;AACvE,CAAC;AAKM,IAAM,iCAAmC,UAAO;AAAA,EACrD,kBAAoB,WAAQ,EAAE,SAAS;AAAA,EACvC,mBAAqB,WAAQ,EAAE,SAAS;AAAA,EACxC,eAAiB,WAAQ,EAAE,SAAS;AAAA,EACpC,eAAiB,UAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC5C,aAAe,UAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1C,oBAAsB,SAAQ,UAAO,CAAC,EAAE,SAAS;AAAA,EACjD,UACG,UAAO;AAAA,IACN,KAAO,UAAO,EAAE,OAAO;AAAA,IACvB,KAAO,UAAO,EAAE,OAAO;AAAA,EACzB,CAAC,EACA,SAAS;AACd,CAAC;AAKM,IAAM,mCAAqC,UAAO;AAAA,EACvD,QAAU,QAAK,CAAC,WAAW,MAAM,CAAC;AAAA,EAClC,UAAY,UAAO,EAAE,IAAI,CAAC;AAAA,EAC1B,MAAQ,UAAO,EAAE,IAAI,CAAC;AAAA,EACtB,iBAAmB,QAAK,CAAC,UAAU,OAAO,CAAC,EAAE,SAAS;AAAA,EACtD,aAAe,UAAO,EAAE,SAAS;AAAA,EACjC,SAAW,UAAO,EAAE,SAAS;AAAA,EAC7B,iBACG;AAAA,IACG,UAAO;AAAA,MACP,KAAO,UAAO,EAAE,IAAI,CAAC;AAAA,MACrB,OAAS,UAAO,EAAE,SAAS;AAAA,MAC3B,QAAU,UAAO,EAAE,OAAO,EAAE,SAAS;AAAA,IACvC,CAAC;AAAA,EACH,EACC,SAAS;AAAA,EACZ,cACG,UAAO;AAAA,IACN,kBAAoB,WAAQ,EAAE,SAAS;AAAA,IACvC,mBAAqB,WAAQ,EAAE,SAAS;AAAA,IACxC,eAAiB,WAAQ,EAAE,SAAS;AAAA,EACtC,CAAC,EACA,SAAS;AACd,CAAC;AAKM,IAAM,kCAAoC,UAAO;AAAA,EACtD,MAAM,6BAA6B,SAAS;AAAA,EAC5C,iBAAmB,UAAO,EAAE,SAAS;AAAA,EACrC,QAAQ,+BAA+B,SAAS;AAAA,EAChD,UAAU,iCAAiC,SAAS;AACtD,CAAC;AAKM,IAAM,2BAA6B,UAAO;AAAA,EAC/C,IAAM,UAAO;AAAA,EACb,OAAS,UAAO;AAAA,EAChB,oBAAsB,WAAQ;AAAA,EAC9B,QAAQ;AAAA,EACR,WAAa,WAAQ,EAAE,SAAS;AAClC,CAAC;AAGM,IAAM,qCAAuC,UAAO;AAAA,EACzD,IAAM,UAAO;AAAA,EACb,QAAQ;AAAA,EACR,UAAU;AAAA,EACV,oBAAsB,WAAQ;AAAA,EAC9B,yBAA2B,WAAQ;AAAA,EACnC,sBAAwB,WAAQ;AAAA,EAChC,qBAAuB,WAAQ;AAAA,EAC/B,wBAA0B,WAAQ;AAAA,EAClC,mBAAqB,WAAQ;AAAA,EAC7B,gBAAkB,UAAO,EAAE,IAAI,EAAE,YAAY;AAAA,EAC7C,gBAAgB;AAClB,CAAC;AAKM,IAAM,sCAAwC,UAAO;AAAA,EAC1D,gBAAkB,UAAO;AAAA,EACzB,QAAU,SAAM,wBAAwB;AAC1C,CAAC;AAKM,IAAM,8CAAgD,UAAO;AAAA,EAClE,SAAW,UAAO,EAAE,IAAI,CAAC;AAC3B,CAAC;AAKM,IAAM,gDAAkD,UAAO;AAAA,EACpE,YAAY;AACd,CAAC;AAKM,IAAM,8BAAgC,UAAO;AAAA,EAClD,SAAW,UAAO;AAAA,EAClB,SAAW,UAAO,EAAE,SAAS;AAAA,EAC7B,MAAM;AAAA,EACN,MAAQ,UAAO,EAAE,SAAS;AAAA,EAC1B,OAAS,UAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EACpC,QAAU,UAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EACrC,YAAY,8BAA8B,SAAS;AAAA,EACnD,WAAa,UAAO,EAAE,SAAS;AACjC,CAAC;AAKM,IAAM,qCAAuC,UAAO;AAAA,EACzD,kBAAoB,WAAQ,EAAE,SAAS;AAAA,EACvC,kBAAoB,WAAQ,EAAE,SAAS;AACzC,CAAC;AAKM,IAAM,uCAAyC,UAAO;AAAA,EAC3D,SAAW,SAAM,2BAA2B;AAC9C,CAAC;AAKM,IAAM,wCAA0C,UAAO;AAAA,EAC5D,kBAAoB,SAAQ,UAAO,CAAC;AAAA,EACpC,SAAW,SAAM,2BAA2B;AAC9C,CAAC;AAKM,IAAM,0CAA4C,UAAO;AAAA,EAC9D,KAAO,UAAO;AAAA,EACd,OAAS,UAAO,EAAE,SAAS;AAAA,EAC3B,QAAU,UAAO,EAAE,OAAO,EAAE,SAAS;AACvC,CAAC;AAKM,IAAM,4BAA8B,UAAO;AAAA,EAChD,IAAM,UAAO;AAAA,EACb,MAAQ,UAAO;AAAA,EACf,QAAU,QAAK,CAAC,WAAW,MAAM,CAAC;AAAA,EAClC,SAAW,UAAO;AAAA,EAClB,YAAc,UAAO,EAAE,SAAS;AAAA,EAChC,eAAiB,UAAO,EAAE,SAAS;AAAA,EACnC,aAAe,UAAO,EAAE,SAAS;AAAA,EACjC,iBAAmB,UAAO,EAAE,SAAS;AAAA,EACrC,QAAU,UAAO,EAAE,SAAS;AAAA,EAC5B,aAAe,UAAO,EAAE,SAAS;AAAA,EACjC,MAAQ,SAAQ,UAAO,CAAC,EAAE,SAAS;AAAA,EACnC,iBAAmB,SAAM,uCAAuC,EAAE,SAAS;AAAA,EAC3E,cAAc,iCAAiC,MAAM,aAAa,SAAS;AAC7E,CAAC;AAKM,IAAM,oCAAsC,UAAO;AAAA,EACxD,IAAM,UAAO;AAAA,EACb,OAAS,UAAO;AAAA,EAChB,aAAe,UAAO,EAAE,SAAS;AACnC,CAAC;AAKM,IAAM,4CAA8C,UAAO;AAAA,EAChE,YAAc,SAAM,iCAAiC;AAAA,EACrD,SAAW,SAAM,yBAAyB;AAC5C,CAAC;AAKM,IAAM,4BAA8B,UAAO;AAAA,EAChD,YAAc,QAAK,CAAC,SAAS,OAAO,CAAC;AAAA,EACrC,SAAW,UAAO;AAAA,EAClB,SAAW,UAAO;AAAA,EAClB,WAAa,UAAO,EAAE,SAAS;AAAA,EAC/B,UAAU,yBAAyB,SAAS;AAC9C,CAAC;AAKM,IAAM,kCAAoC,UAAS,UAAO,GAAG,SAAS;AAKtE,IAAM,iCAAmC,UAAO;AAAA,EACrD,kBAAoB,UAAO,EAAE,SAAS;AAAA,EACtC,cAAc,gCAAgC,SAAS;AAAA,EACvD,qBACG,UAAO;AAAA,IACN,MAAQ,WAAQ;AAAA,IAChB,YAAc,QAAK,CAAC,uBAAuB,wBAAwB,CAAC;AAAA,IACpE,iBAAmB,UAAO,EAAE,SAAS;AAAA,EACvC,CAAC,EACA,SAAS;AACd,CAAC;AAKM,IAAM,kCAAoC,UAAO;AAAA,EACtD,eAAiB,UAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,QAAU,UAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAI;AAAA,EAClC,SAAW,UAAO,EAAE,SAAS;AAAA,EAC7B,mBAAqB,SAAQ,UAAO,CAAC,EAAE,IAAI,EAAE,EAAE,SAAS;AAAA,EACxD,mBAAqB,QAAK,CAAC,OAAO,UAAU,MAAM,CAAC,EAAE,SAAS;AAAA,EAC9D,eAAe,iCAAiC,SAAS;AAAA,EACzD,MAAM,+BAA+B,SAAS;AAAA,EAC9C,YAAY,8BAA8B,SAAS;AAAA,EACnD,gBAAgB,kCAAkC,SAAS;AAAA,EAC3D,OAAO,gCAAgC,SAAS;AAAA,EAChD,SAAS,2BAA2B,SAAS;AAC/C,CAAC;AAKM,IAAM,+BAAiC,UAAO;AAAA,EACnD,OAAS,UAAO,EAAE,SAAS;AAAA,EAC3B,QAAQ,0BAA0B,SAAS;AAAA,EAC3C,SAAW,SAAM,yBAAyB,EAAE,SAAS;AAAA,EACrD,UAAU,+BAA+B,SAAS;AACpD,CAAC;AAKM,IAAM,gCAAkC,UAAO;AAAA,EACpD,eAAiB,UAAO,EAAE,IAAI,CAAC;AAAA,EAC/B,eACG,SAAM,CAAG,WAAQ,GAAG,GAAK,WAAQ,CAAC,GAAK,WAAQ,CAAC,CAAC,CAAC,EAClD,SAAS;AAAA,EACZ,SAAS,2BAA2B,SAAS;AAC/C,CAAC;AAKM,IAAM,iCAAmC,UAAO;AAAA,EACrD,aAAe,UAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACrD,YAAc,UAAO,EAAE,IAAI,EAAE,YAAY,EAAE,SAAS;AAAA,EACpD,SAAW,UAAO,EAAE,SAAS;AAC/B,CAAC;AAKM,IAAM,yBAA2B,UAAO;AAAA,EAC7C,OAAS,UAAO;AAAA,EAChB,QAAQ;AAAA,EACR,WAAa,UAAO;AAAA,EACpB,WAAa,UAAO;AAAA,EACpB,aAAe,UAAO,EAAE,SAAS;AAAA,EACjC,QAAU,UAAO;AAAA,EACjB,UAAU,+BAA+B,SAAS;AAAA,EAClD,QAAQ,6BAA6B,SAAS;AAAA,EAC9C,OAAS,UAAO,EAAE,SAAS;AAC7B,CAAC;AAGM,IAAM,6BAA+B,UAAO;AAAA,EACjD,OAAS,UAAO,EAAE,IAAI,CAAC;AACzB,CAAC;AAKM,IAAM,kCAAoC,UAAO;AAAA,EACtD,KAAK;AACP,CAAC;AAKM,IAAM,qCAAuC,UAAO;AAAA,EACzD,KAAK;AACP,CAAC;AAKM,IAAM,oCAAsC,UAAO;AAAA,EACxD,MAAQ,SAAM,sBAAsB;AACtC,CAAC;AAKM,IAAM,yCAA2C,UAAO;AAAA,EAC7D,MAAQ,UAAO,EAAE,SAAS;AAAA,EAC1B,QAAU,UAAO,EAAE,SAAS;AAAA,EAC5B,UAAY,UAAO,EAAE,SAAS;AAAA,EAC9B,iBAAmB,UAAO,EAAE,SAAS;AACvC,CAAC;AAKM,IAAM,6CAA+C,UAAO;AAAA,EACjE,SAAW,WAAQ,CAAC;AAAA,EACpB,MAAQ,UAAS,UAAO,GAAG,SAAS;AAAA,EACpC,YAAY,8BAA8B,SAAS;AAAA,EACnD,gBAAkB,UAAS,UAAO,GAAG,SAAS,EAAE,SAAS;AAAA,EACzD,qBAAuB,UAAO,EAAE,OAAO,EAAE,SAAS;AACpD,CAAC;AAKM,IAAM,uCAAyC,UAAO;AAAA,EAC3D,MAAQ,QAAK,CAAC,kBAAkB,UAAU,gBAAgB,CAAC;AAAA,EAC3D,OAAS,UAAO;AAAA,EAChB,QAAU,UAAO,EAAE,SAAS;AAAA,EAC5B,SAAW,UAAO,EAAE,SAAS;AAAA,EAC7B,UAAY,UAAO,EAAE,SAAS;AAAA,EAC9B,YAAc,UAAO,EAAE,SAAS;AAAA,EAChC,cAAgB,UAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3C,YAAc,QAAK,CAAC,WAAW,WAAW,CAAC,EAAE,SAAS;AAAA,EACtD,OAAO,uCAAuC,SAAS;AAAA,EACvD,iBAAiB,2CAA2C,SAAS;AACvE,CAAC;AAKM,IAAM,kCAAoC,UAAO;AAAA,EACtD,IAAM,UAAO;AAAA,EACb,SAAW,UAAO;AAAA,EAClB,SAAW,UAAO,EAAE,SAAS;AAAA,EAC7B,MAAM;AAAA,EACN,OAAS,UAAO;AAAA,EAChB,UAAU,oCAAoC,SAAS;AAAA,EACvD,aAAe,UAAO,EAAE,SAAS;AAAA,EACjC,iBAAmB,SAAQ,UAAO,CAAC;AAAA,EACnC,iBAAmB,SAAQ,UAAO,CAAC;AAAA,EACnC,WAAa,UAAO;AAAA,EACpB,WAAa,UAAO;AACtB,CAAC;AAKM,IAAM,kCAAoC,UAAO;AAAA,EACtD,IAAM,UAAO;AAAA,EACb,cAAgB,UAAO;AAAA,EACvB,cAAgB,UAAO;AAAA,EACvB,cAAgB,UAAO,EAAE,SAAS;AAAA,EAClC,WAAW;AAAA,EACX,OAAS,UAAO;AAAA,EAChB,UAAU,oCAAoC,SAAS;AAAA,EACvD,aAAe,UAAO,EAAE,SAAS;AAAA,EACjC,oBAAsB,UAAO,EAAE,SAAS;AAAA,EACxC,WAAa,UAAO;AAAA,EACpB,WAAa,UAAO;AACtB,CAAC;AAKM,IAAM,8BAAgC,UAAO;AAAA,EAClD,IAAM,UAAO;AAAA,EACb,aAAe,SAAQ,UAAO,CAAC;AAAA,EAC/B,SAAW,SAAQ,UAAO,CAAC;AAAA,EAC3B,SAAW,SAAQ,UAAO,CAAC;AAAA,EAC3B,OAAS,UAAS,UAAO,GAAG,+BAA+B;AAAA,EAC3D,OAAS,UAAS,UAAO,GAAG,+BAA+B;AAAA,EAC3D,WAAa,UAAO;AAAA,EACpB,WAAa,UAAO;AACtB,CAAC;AAKM,IAAM,6CAA+C,UAAO;AAAA,EACjE,SAAW,UAAO,EAAE,IAAI,CAAC;AAC3B,CAAC;AAKM,IAAM,+CAAiD,UAAO;AAAA,EACnE,UAAU,4BAA4B,SAAS;AAAA,EAC/C,MAAM,gCAAgC,SAAS;AACjD,CAAC;AAKM,IAAM,qCAAuC;AAAA,EAClD;AAAA,EACA;AAAA,IACI,UAAO;AAAA,MACP,QAAU,WAAQ,OAAO;AAAA,MACzB,YAAc,UAAO;AAAA,MACrB,YAAY;AAAA,MACZ,SAAW,SAAQ,UAAO,CAAC;AAAA,MAC3B,OAAS,SAAM,+BAA+B;AAAA,MAC9C,QAAU,QAAK,MAAM,yBAAyB;AAAA,MAC9C,eAAiB,WAAQ;AAAA,MACzB,wBAA0B,UAAO,EAAE,SAAS;AAAA,IAC9C,CAAC;AAAA,IACC,UAAO;AAAA,MACP,QAAU,WAAQ,aAAa;AAAA,MAC/B,QAAU,QAAK;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;AAKO,IAAM,6CAA+C,UAAO;AAAA,EACjE,SAAW,UAAO,EAAE,IAAI,CAAC;AAAA,EACzB,iBAAmB,UAAO,EAAE,SAAS;AAAA,EACrC,SAAS,2BAA2B,SAAS;AAC/C,CAAC;AAKM,IAAM,gCAAkC,UAAO;AAAA,EACpD,IAAM,UAAO;AAAA,EACb,MAAQ,QAAK,CAAC,gBAAgB,WAAW,CAAC;AAAA,EAC1C,OAAS,UAAO;AAAA,EAChB,UAAY,WAAQ;AACtB,CAAC;AAKM,IAAM,gCAAkC,UAAO;AAAA,EACpD,IAAM,UAAO;AAAA,EACb,WAAW;AAAA,EACX,YAAc,QAAK,CAAC,SAAS,OAAO,CAAC;AACvC,CAAC;AAKM,IAAM,iCAAmC,UAAO;AAAA,EACrD,MAAQ,UAAO;AAAA,EACf,SAAW,UAAO;AAAA,EAClB,OAAS,SAAM,6BAA6B;AAAA,EAC5C,OAAS,SAAM,6BAA6B,EAAE,IAAI,CAAC,EAAE,IAAI,EAAE;AAAA,EAC3D,YAAc,QAAK,CAAC,SAAS,OAAO,CAAC;AAAA,EACrC,cAAgB,UAAO,EAAE,SAAS;AACpC,CAAC;AAKM,IAAM,4BAQT,+BAA+B,OAAO;AAAA,EACxC,SAAW,WAAQ,CAAC;AAAA,EACpB,IAAM,UAAO;AAAA,EACb,aAAe,UAAO,EAAE,SAAS;AAAA,EACjC,WAAa,UAAO;AAAA,EACpB,WAAa,UAAO;AACtB,CAAC;AAKM,IAAM,sCAAwC;AAAA,EACnD;AAAA,EACA;AAAA,IACI,UAAO;AAAA,MACP,QAAU,WAAQ,OAAO;AAAA,MACzB,OAAO;AAAA,IACT,CAAC;AAAA,IACC,UAAO;AAAA,MACP,QAAU,WAAQ,aAAa;AAAA,MAC/B,QAAU,QAAK;AAAA,QACb;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,QACA;AAAA,MACF,CAAC;AAAA,IACH,CAAC;AAAA,EACH;AACF;AAKO,IAAM,uCAAyC,UAAO;AAAA,EAC3D,SAAW,SAAM,yBAAyB;AAC5C,CAAC;AAKM,IAAM,oCAAsC,UAAO;AAAA,EACxD,OAAO;AAAA,EACP,MAAQ,UAAO,EAAE,IAAI,CAAC;AACxB,CAAC;AAKM,IAAM,sCAAwC;AAAA,EACnD;AAAA,EACA;AAAA,IACI,UAAO,EAAE,QAAU,WAAQ,OAAO,GAAG,QAAQ,0BAA0B,CAAC;AAAA,IACxE,UAAO;AAAA,MACP,QAAU,WAAQ,WAAW;AAAA,MAC7B,QAAQ;AAAA,IACV,CAAC;AAAA,IACC,UAAO,EAAE,QAAU,WAAQ,cAAc,GAAG,QAAU,QAAK,EAAE,CAAC;AAAA,IAC9D,UAAO,EAAE,QAAU,WAAQ,QAAQ,GAAG,QAAU,QAAK,EAAE,CAAC;AAAA,EAC5D;AACF;AAKO,IAAM,sCAAwC,UAAO;AAAA,EAC1D,UAAY,UAAO,EAAE,IAAI,CAAC;AAC5B,CAAC;AAKM,IAAM,wCAA0C,UAAO;AAAA,EAC5D,SAAW,WAAQ;AACrB,CAAC;AAKM,IAAM,gDAAkD,UAAO;AAAA,EACpE,SAAW,UAAO,EAAE,IAAI,CAAC;AAC3B,CAAC;AAKM,IAAM,mCAAqC,UAAO;AAAA,EACvD,UAAY,UAAO,EAAE,SAAS;AAAA,EAC9B,QAAQ,0BAA0B,SAAS;AAAA,EAC3C,cAAgB,UAAS,UAAO,GAAK,UAAO,CAAC;AAAA,EAC7C,SAAS,2BAA2B,SAAS;AAC/C,CAAC;AAcM,IAAe,sCAAf,MAAmD;AAAA,EACxD,cAAc;AAAA,EAAC;AAyJjB;;;AC/1BO,IAAe,yBAAf,MAAsC;AAAA,EAI3C,cAAc;AAAA,EAAC;AACjB;;;ACZA,YAAYC,QAAO;AAaZ,IAAe,6BAAf,MAA0C;AAAA,EAC/C,cAAc;AAAA,EAAC;AAgEjB;AAQO,IAAM,uCAAyC,SAAM;AAAA,EACxD,UAAO,EAAE,GAAK,UAAO,EAAE,OAAO,GAAG,GAAK,UAAO,EAAE,OAAO,EAAE,CAAC,EAAE,OAAO;AAAA,EAClE,SAAM,CAAG,UAAO,EAAE,OAAO,GAAK,UAAO,EAAE,OAAO,CAAC,CAAC;AACpD,CAAC;AAgBM,IAAM,qCAAuC,sBAAmB,QAAQ;AAAA,EAC3E,UAAO;AAAA,IACP,MAAQ,WAAQ,YAAY;AAAA,IAC5B,WAAa,UAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC1C,CAAC,EAAE,OAAO;AAAA,EACR,UAAO;AAAA,IACP,MAAQ,WAAQ,YAAY;AAAA,IAC5B,WAAa,UAAO,EAAE,OAAO,EAAE,IAAI,EAAE,SAAS;AAAA,EAChD,CAAC,EAAE,OAAO;AACZ,CAAC;AAyBM,IAAM,qCAAuC,UAAO;AAAA,EACzD,aAAe,UAAO,EAAE,OAAO,EAAE,YAAY;AAAA,EAC7C,OAAS,UAAO,EAAE,OAAO,EAAE,YAAY;AAAA,EACvC,MAAQ,UAAO,EAAE,OAAO,EAAE,YAAY;AAAA,EACtC,MAAQ,UAAO,EAAE,OAAO,EAAE,YAAY;AACxC,CAAC,EAAE,OAAO;AAUV,SAAS,mBACP,MACA,KACM;AACN,QAAM,QAAQ,KAAK;AACnB,MAAI,MAAM,WAAW,EAAG;AACxB,MAAI,MAAM,CAAC,EAAE,gBAAgB,GAAG;AAC9B,QAAI,SAAS;AAAA,MACX,MAAQ,gBAAa;AAAA,MACrB,MAAM,CAAC,YAAY,GAAG,aAAa;AAAA,MACnC,SAAS;AAAA,IACX,CAAC;AAAA,EACH;AACA,WAAS,IAAI,GAAG,IAAI,MAAM,QAAQ,KAAK;AACrC,QAAI,EAAE,MAAM,CAAC,EAAE,cAAc,MAAM,IAAI,CAAC,EAAE,cAAc;AACtD,UAAI,SAAS;AAAA,QACX,MAAQ,gBAAa;AAAA,QACrB,MAAM,CAAC,YAAY,GAAG,aAAa;AAAA,QACnC,SACE;AAAA,MACJ,CAAC;AAAA,IACH;AAAA,EACF;AACF;AAmBO,IAAM,oCACV,UAAO;AAAA,EACN,aAAe,SAAM,oCAAoC,EAAE,IAAI,CAAC;AAAA,EAChE,YAAc,SAAM,CAAG,WAAQ,IAAI,GAAK,WAAQ,GAAG,CAAC,CAAC;AAAA,EACrD,UAAY,SAAM,kCAAkC,EAAE,IAAI,CAAC;AAAA,EAC3D,aAAa;AAAA,EACb,cAAgB,UAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3C,UAAY,UAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAClD,mBAAqB,UAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AAClE,CAAC,EACA,OAAO,EACP,YAAY,kBAAkB;AAa1B,IAAM,sCAAwC,UAAO;AAAA,EAC1D,qBAAuB,UAAO,EAAE,IAAI,CAAC;AACvC,CAAC,EAAE,OAAO;AAuBH,IAAM,oCACV,UAAO;AAAA,EACN,qBAAuB,UAAO,EAAE,IAAI,CAAC;AAAA,EACrC,aAAe,SAAM,oCAAoC,EAAE,IAAI,CAAC;AAAA,EAChE,YAAc,SAAM,CAAG,WAAQ,IAAI,GAAK,WAAQ,GAAG,CAAC,CAAC;AAAA,EACrD,UAAY,SAAM,kCAAkC,EAAE,IAAI,CAAC;AAAA,EAC3D,aAAa;AAAA,EACb,cAAgB,UAAO,EAAE,OAAO,EAAE,SAAS;AAAA,EAC3C,UAAY,UAAO,EAAE,OAAO,EAAE,SAAS,EAAE,SAAS;AAAA,EAClD,mBAAqB,UAAO,EAAE,OAAO,EAAE,IAAI,CAAC,EAAE,IAAI,GAAG,EAAE,SAAS;AAClE,CAAC,EACA,OAAO,EACP,YAAY,kBAAkB;AAa1B,IAAM,sCAAwC,UAAO;AAAA,EAC1D,qBAAuB,UAAO,EAAE,IAAI,CAAC;AACvC,CAAC,EAAE,OAAO;;;AChRV,YAAYC,QAAO;AAYZ,IAAe,sBAAf,MAAmC;AAAA,EACxC,cAAc;AAAA,EAAC;AAyCjB;AAUO,IAAM,6BAA+B,UAAO;AAAA,EACjD,MAAQ,UAAO;AAAA,EACf,OAAS,UAAO;AAClB,CAAC;AAaM,IAAM,+BAAiC,UAAO;AAAA,EACnD,cAAgB,UAAO;AACzB,CAAC;AASM,IAAM,wBAA0B,UAAO;AAAA,EAC5C,IAAM,UAAO;AAAA,EACb,MAAQ,UAAO;AAAA,EACf,OAAS,UAAO;AAClB,CAAC;AAWM,IAAM,+BAAiC,UAAO;AAAA,EACnD,aAAe,SAAM,qBAAqB;AAC5C,CAAC;;;AC5GD,YAAYC,SAAO;AAiBZ,IAAe,yBAAf,MAAsC;AAAA,EAC3C,cAAc;AAAA,EAAC;AAqGjB;AASO,IAAM,qCAAuC,WAAO;AAAA,EACzD,SAAS;AACX,CAAC;AAWM,IAAM,uCAAyC,WAAO;AAAA,EAC3D,kBAAoB,UAAQ,WAAO,CAAC;AACtC,CAAC;AAWM,IAAM,iCAAmC,SAAK;AAAA,EACnD;AACF,CAAC;AAUM,IAAM,6BAA+B,WAAO;AAAA,EACjD,iBAAmB,WAAO;AAAA,EAC1B,YAAc,UAAM,8BAA8B;AACpD,CAAC;AAUM,IAAM,+BACV,WAAO;AAAA,EACN,OAAO;AACT,CAAC,EACA,QAAQ;AAWJ,IAAM,kCAAoC,WAAO;AAAA,EACtD,kBAAoB,UAAQ,WAAO,CAAC;AACtC,CAAC;AAWM,IAAM,gCAAkC,WAAO;AAAA,EACpD,iBAAmB,WAAO;AAC5B,CAAC;;;ACjND,YAAYC,SAAO;AAkBZ,IAAe,iBAAf,MAA8B;AAAA,EACnC,cAAc;AAAA,EAAC;AAoWjB;AAUO,IAAM,mCAAqC,WAAO;AAAA,EACvD,UAAU;AAAA,EACV,YAAc,WAAO;AAAA,IACnB,OAAS,WAAO;AAAA,IAChB,QAAU,WAAO;AAAA,IACjB,OAAS,WAAO;AAAA,EAClB,CAAC;AACH,CAAC;AAaM,IAAM,qCAAuC,WAAO;AAAA,EACzD,SAAW,WAAO;AACpB,CAAC;AAgBM,IAAM,mCAAqC,WAAO;AAAA,EACvD,SAAS;AAAA,EACT,eAAiB,UAAM,QAAQ,EAAE,SAAS;AAAA,EAC1C,eAAiB,WAAO;AAAA,EACxB,UAAU;AACZ,CAAC;AAaM,IAAM,qCAAuC,WAAO;AAAA,EACzD,SAAW,WAAO;AACpB,CAAC;AAeM,IAAM,2CAA6C,WAAO;AAAA,EAC/D,SAAW,WAAO;AAAA,EAClB,SAAS;AAAA,EACT,eAAiB,WAAO;AAC1B,CAAC;AAaM,IAAM,6CAA+C,WAAO;AAAA,EACjE,SAAW,WAAO;AACpB,CAAC;AAgDM,IAAM,yBAA2B,SAAK;AAAA;AAAA,EAE3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA;AAAA,EAEA;AACF,CAAC;AAUM,IAAM,qBAAuB,WAAO;AAAA,EACzC,SAAW,WAAO;AAAA,EAClB,YAAc,UAAM,sBAAsB;AAC5C,CAAC;AAsBM,IAAM,kBAAoB,SAAK;AAAA,EACpC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAeM,IAAM,kBAAoB,SAAK,CAAC,OAAO,SAAS,UAAU,CAAC;AAQ3D,IAAM,uBACV,WAAO;AAAA;AAAA,EAEN,IAAM,WAAO;AAAA,EACb,MAAQ,WAAO;AAAA,EACf,WAAa,WAAO;AAAA,EACpB,MAAQ,WAAO;AAAA;AAAA,EAEf,MAAQ,WAAO;AAAA,EACf,SAAW,WAAO;AAAA,EAClB,OAAS,WAAO;AAAA,EAChB,QAAU,WAAO;AAAA,EACjB,UAAY,WAAO,EAAE,SAAS;AAAA,EAC9B,WAAW,gBAAgB,SAAS;AAAA,EACpC,WAAW;AAAA,EACX,QAAU,WAAO,EAAE,SAAS;AAAA,EAC5B,cAAgB,WAAO,EAAE,SAAS;AAAA,EAClC,gBAAkB,WAAO;AAAA,EACzB,iBAAmB,WAAO;AAAA;AAAA,EAE1B,UAAU;AAAA,EACV,kBAAkB;AAAA,EAClB,UAAU;AAAA,EACV,oBAAoB,MAAM,SAAS;AAAA;AAAA,EAEnC,YAAc,UAAM,KAAK;AAAA,EACzB,SAAS;AAAA,EACT,eAAiB,UAAM,QAAQ;AAAA,EAC/B,iBAAmB,UAAQ,UAAM,KAAK,CAAC;AAAA;AAAA,EAEvC,WAAa,UAAQ,WAAO;AAAA,IAC1B,SAAW,WAAO;AAAA,IAClB,OAAS,WAAO;AAAA,EAClB,CAAC,CAAC;AACJ,CAAC,EACA,QAAQ;AAWJ,IAAM,0BAA4B,WAAO;AAAA,EAC9C,WAAa,UAAQ,WAAO,CAAC;AAC/B,CAAC;AAWM,IAAM,wBAA0B,WAAO;AAAA,EAC5C,SAAW,WAAO;AACpB,CAAC;AA2BM,IAAM,iBAAmB,SAAK;AAAA,EACnC;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAYM,IAAM,8BAAgC,SAAK;AAAA,EAChD;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAMM,IAAM,qBAAuB,UAAM;AAAA,EACxC;AAAA,EACE,SAAK;AACT,CAAC;AAcM,IAAM,wBAA0B,WAAO;AAAA,EAC5C,SAAW,WAAO;AAAA,EAClB,YAAc,WAAO;AAAA,IACnB,WAAa,WAAO,EAAE,SAAS;AAAA,IAC/B,UAAU,eAAe,SAAS;AAAA,IAClC,WAAW,gBAAgB,SAAS;AAAA,IACpC,WAAW,gBAAgB,SAAS;AAAA,IACpC,cAAc,mBAAmB,SAAS;AAAA,EAC5C,CAAC;AACH,CAAC;AAmBM,IAAM,0BAA4B,WAAO;AAAA,EAC9C,SAAW,WAAO;AAAA,EAClB,WAAa,WAAO,EAAE,SAAS;AAAA,EAC/B,UAAY,WAAO,EAAE,SAAS;AAAA,EAC9B,WAAa,WAAO,EAAE,SAAS;AAAA,EAC/B,WAAW,gBAAgB,SAAS;AAAA,EACpC,cAAgB,WAAO,EAAE,SAAS,EAAE,SAAS;AAC/C,CAAC;AAqBM,IAAM,4BAA8B,uBAAmB,QAAQ;AAAA,EAClE,WAAO;AAAA,IACP,MAAQ,YAAQ,aAAa;AAAA,IAC7B,UAAU;AAAA,IACV,YAAc,WAAO;AAAA,MACnB,OAAS,WAAO;AAAA,MAChB,QAAU,WAAO;AAAA,MACjB,OAAS,WAAO;AAAA,IAClB,CAAC;AAAA,IACD,WAAa,WAAO,EAAE,SAAS;AAAA,IAC/B,WAAW,gBAAgB,SAAS;AAAA,IACpC,UAAU,eAAe,SAAS;AAAA,IAClC,cAAc,mBAAmB,SAAS;AAAA,EAC5C,CAAC;AAAA,EACC,WAAO;AAAA,IACP,MAAQ,YAAQ,SAAS;AAAA,IACzB,SAAS;AAAA,IACT,eAAiB,UAAM,QAAQ,EAAE,SAAS;AAAA,IAC1C,eAAiB,WAAO;AAAA,IACxB,UAAU;AAAA,IACV,WAAa,WAAO,EAAE,SAAS;AAAA,IAC/B,WAAW,gBAAgB,SAAS;AAAA,IACpC,UAAU,eAAe,SAAS;AAAA,IAClC,cAAc,mBAAmB,SAAS;AAAA,EAC5C,CAAC;AACH,CAAC;AAWM,IAAM,4BAA8B,WAAO;AAAA,EAChD,OAAS,UAAM,yBAAyB;AAC1C,CAAC;AAWM,IAAM,8BAAgC,WAAO;AAAA,EAClD,UAAY,UAAQ,WAAO,CAAC;AAC9B,CAAC;AAqBM,IAAM,4BAA8B,WAAO;AAAA,EAChD,SAAW,WAAO;AAAA,EAClB,SAAS,SAAS,SAAS;AAAA,EAC3B,eAAiB,WAAO,EAAE,SAAS;AAAA,EACnC,YACG,WAAO;AAAA,IACN,WAAa,WAAO,EAAE,SAAS;AAAA,IAC/B,UAAU,eAAe,SAAS;AAAA,IAClC,WAAW,gBAAgB,SAAS;AAAA,IACpC,WAAW,gBAAgB,SAAS;AAAA,IACpC,cAAc,mBAAmB,SAAS;AAAA,EAC5C,CAAC,EACA,SAAS;AACd,CAAC;AAWM,IAAM,4BAA8B,WAAO;AAAA,EAChD,OAAS,UAAM,yBAAyB;AAC1C,CAAC;AAcM,IAAM,8BAAgC,WAAO;AAAA,EAClD,QAAU,UAAM,uBAAuB;AACzC,CAAC;AAaM,IAAM,4BAA8B,WAAO;AAAA,EAChD,UAAY,UAAQ,WAAO,CAAC;AAC9B,CAAC;AAWM,IAAM,8BAAgC,WAAO;AAAA,EAClD,iBAAmB,UAAQ,WAAO,CAAC;AACrC,CAAC;;;ACn8BD,YAAYC,SAAO;AAeZ,IAAe,iBAAf,MAA8B;AAAA,EACnC,cAAc;AAAA,EAAC;AAyGjB;AAgBO,IAAM,yBAA2B,SAAK;AAAA,EAC3C;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAUM,IAAM,qBAAuB,WAAO;AAAA,EACzC,YAAc,WAAO,EAAE,IAAI;AAAA,EAC3B,YAAc,UAAM,sBAAsB;AAC5C,CAAC;AAUM,IAAM,uBACV,WAAO;AAAA,EACN,OAAS,WAAO;AAAA,EAChB,IAAM,WAAO;AAAA,EACb,MAAQ,WAAO;AAAA,EACf,QAAU,WAAO;AAAA,EACjB,MAAQ,WAAO;AAAA,EACf,QAAU,YAAQ;AAAA,EAClB,aAAe,WAAO;AAAA,EACtB,WAAa,WAAO;AACtB,CAAC,EACA,QAAQ;AAWJ,IAAM,0BAA4B,WAAO;AAAA,EAC9C,SAAW;AAAA,IACP,WAAO;AAAA,MACP,OAAS,WAAO;AAAA,MAChB,IAAM,WAAO;AAAA,MACb,MAAQ,WAAO;AAAA,IACjB,CAAC;AAAA,EACH;AACF,CAAC;AAYM,IAAM,wBAA0B,WAAO;AAAA,EAC5C,YAAc,WAAO,EAAE,IAAI;AAAA,EAC3B,QAAU,WAAO,EAAE,SAAS;AAC9B,CAAC;AAYM,IAAM,0BAA4B,WAAO;AAAA,EAC9C,SAAW,WAAO;AAAA,EAClB,YAAc,WAAO;AACvB,CAAC;AAYM,IAAM,wBAA0B,WAAO;AAAA,EAC5C,YAAc,WAAO,EAAE,IAAI;AAAA,EAC3B,QAAU,WAAO;AACnB,CAAC;AAYM,IAAM,0BAA4B,WAAO;AAAA,EAC9C,YAAc,WAAO;AAAA,EACrB,QAAU,WAAO;AACnB,CAAC;;;ACpPM,IAAe,kBAAf,MAA+B;AAAA,EAYpC,cAAc;AAAA,EAAC;AACjB;;;AC5BA,YAAYC,SAAO;AAYZ,IAAM,iBAAmB,SAAK,CAAC,YAAY,QAAQ,CAAC;AAqBpD,IAAM,iBAAmB,WAAO;AAAA,EACrC,cAAgB,UAAQ,WAAO,CAAC,EAAE,IAAI,CAAC;AAAA,EACvC,cAAc;AAAA,EACd,OAAS,WAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS;AAAA,EAC5C,UAAU,eAAe,SAAS;AACpC,CAAC;AAUM,IAAM,mBAAqB,WAAO;AAAA,EACvC,WAAa,UAAQ,WAAO,CAAC;AAC/B,CAAC;;;AClDD,YAAYC,SAAO;AAoBZ,IAAM,mBAAqB,WAAO;AAAA,EACvC,aAAe,WAAO,EAAE,IAAI,CAAC;AAAA,EAC7B,UAAY,WAAO;AAAA,EACnB,kBAAkB,MAAM,SAAS;AACnC,CAAC;AAUM,IAAM,qBAAuB,WAAO;AAAA,EACzC,YAAc,UAAQ,WAAO,CAAC;AAAA,EAC9B,YAAc,UAAQ,WAAO,CAAC;AAChC,CAAC;;;ACrCD,YAAYC,SAAO;AAQZ,IAAe,qBAAf,MAAkC;AAAA,EACvC,cAAc;AAAA,EAAC;AA4BjB;AASO,IAAM,2BAA6B,WAAO;AAAA,EAC/C,UAAY,UAAQ,WAAO,CAAC;AAC9B,CAAC;;;AChDD,YAAYC,SAAO;AAaZ,IAAe,qBAAf,MAAkC;AAAA,EACvC,cAAc;AAAA,EAAC;AAoEjB;AAUO,IAAM,iBAAmB,WAAO;AAAA,EACrC,cAAgB,UAAQ,WAAO,CAAC;AAAA,EAChC,cAAc;AAChB,CAAC;AAcM,IAAM,mBAAqB,WAAO;AAAA,EACvC,cAAgB,UAAQ,WAAO,CAAC;AAAA,EAChC,OAAS,WAAO;AAAA,EAChB,MAAM;AAAA,EACN,OAAO;AACT,CAAC;;;ACpGM,IAAe,iBAAf,MAA8B;AAAA,EAcnC,cAAc;AAAA,EAAC;AACjB;;;AC7BA,YAAYC,SAAO;AAaZ,IAAe,iBAAf,MAA8B;AAAA,EACnC,cAAc;AAAA,EAAC;AAiEjB;AAaO,IAAM,YAAc,SAAK;AAAA,EAC9B;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AAAA,EACA;AACF,CAAC;AAaM,IAAM,6BAA+B,WAAO;AAAA,EACjD,MAAM;AAAA,EACN,OAAS,WAAO;AAAA,EAChB,QAAU,WAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAClD,CAAC;AAWM,IAAM,+BAAiC,WAAO;AAAA,EACnD,OAAS,WAAO;AAClB,CAAC;AAaM,IAAM,2BAA6B,WAAO;AAAA,EAC/C,MAAM;AAAA,EACN,OAAS,WAAO;AAAA,EAChB,QAAU,WAAO,EAAE,IAAI,EAAE,IAAI,CAAC,EAAE,IAAI,CAAC,EAAE,SAAS;AAClD,CAAC;AAWM,IAAM,6BAA+B,WAAO;AAAA,EACjD,OAAS,WAAO;AAClB,CAAC;;;AC/IM,IAAe,YAAf,MAAyB;AAAA,EAY9B,cAAc;AAAA,EAAC;AACjB;","names":["z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z"]}
1
+ {"version":3,"sources":["../src/api/core/math/vec3.ts","../src/api/core/math/quat.ts","../src/api/core/math/index.ts","../src/api/core/geom/create/index.ts","../src/handles.ts","../src/api/core/geom/query/curve.ts","../src/api/core/geom/query/arc.ts","../src/api/core/geom/query/circle.ts","../src/api/core/geom/query/profile.ts","../src/api/core/geom/query/contour.ts","../src/api/core/geom/query/brep.ts","../src/api/core/geom/query/face.ts","../src/api/core/geom/query/edge.ts","../src/api/core/geom/query/halfedge.ts","../src/api/core/geom/query/vertex.ts","../src/api/core/geom/query/index.ts","../src/api/core/geom/update/curve.ts","../src/api/core/geom/update/profile.ts","../src/api/core/geom/update/contour.ts","../src/api/core/geom/update/index.ts","../src/api/core/geom/delete/index.ts","../src/api/core/geom/index.ts","../src/api/core/history/index.ts","../src/api/core/units/index.ts","../src/api/core/zoom/index.ts","../src/api/core/project/index.ts","../src/api/core/comment/index.ts","../src/api/core/groups.ts","../src/api/core/buildings.ts","../src/api/core/layers.ts","../src/api/core/tags.ts","../src/api/core/index.ts","../src/api/design/create/index.ts","../src/api/entity/space.ts","../src/api/design/query/index.ts","../src/api/design/query/geometry/index.ts","../src/api/design/query/spaces.ts","../src/api/design/selection/index.ts","../src/api/design/doors/index.ts","../src/api/design/windows/index.ts","../src/api/design/furniture/index.ts","../src/api/design/materials/index.ts","../src/api/design/lock.ts","../src/api/design/erase/index.ts","../src/api/design/delete/index.ts","../src/api/design/shared.ts","../src/api/design/boolean/index.ts","../src/api/design/transform/index.ts","../src/api/design/edit/index.ts","../src/api/design/update/index.ts","../src/api/design/index.ts","../src/api/entity/buildableEnvelope.ts","../src/api/entity/referenceLine.ts","../src/api/entity/story.ts","../src/api/entity/index.ts","../src/api/program/departments.ts","../src/api/program/metrics.ts","../src/api/program/adjacency.ts","../src/api/program/layout.ts","../src/api/program/spreadsheet.ts","../src/api/program/site.ts","../src/api/program/cores.ts","../src/api/program/classification.ts","../src/api/program/areas.ts","../src/api/program/index.ts","../src/api/presentation/views.ts","../src/api/presentation/sheets.ts","../src/api/presentation/diagrams.ts","../src/api/presentation/import.ts","../src/api/presentation/aiInspiration.ts","../src/api/presentation/index.ts","../src/api/index.ts"],"sourcesContent":["import { PluginApiReturn } from \"../../../types\"\nimport { Vec3Handle, Vec3Components } from \"../../../handles\"\n\n/**\n * 3D vector operations (all-handle model, §11).\n *\n * Vectors are opaque {@linkcode Vec3Handle}s; every operation is a host call\n * returning a new handle (vectors are immutable). Read primitive components back\n * with {@linkcode PluginVec3Api.components}. Accessed via `snaptrude.core.math.vec3`.\n */\nexport abstract class PluginVec3Api {\n constructor() {}\n\n /**\n * Create a vector from primitive components.\n *\n * # Example\n * ```ts\n * const v = await snaptrude.core.math.vec3.new(10, 0, 5)\n * const { x, y, z } = await snaptrude.core.math.vec3.components(v)\n * ```\n */\n abstract new(x: number, y: number, z: number): PluginApiReturn<Vec3Handle>\n /**\n * Add two vectors component-wise (`a + b`).\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(1, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const sum = await snaptrude.core.math.vec3.add(a, b)\n * ```\n */\n abstract add(a: Vec3Handle, b: Vec3Handle): PluginApiReturn<Vec3Handle>\n /**\n * Subtract vector `b` from `a` component-wise (`a - b`).\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(3, 2, 1)\n * const b = await snaptrude.core.math.vec3.new(1, 1, 1)\n * const diff = await snaptrude.core.math.vec3.subtract(a, b)\n * ```\n */\n abstract subtract(a: Vec3Handle, b: Vec3Handle): PluginApiReturn<Vec3Handle>\n /**\n * Scale `v` by a scalar.\n *\n * # Example\n * ```ts\n * const v = await snaptrude.core.math.vec3.new(1, 2, 3)\n * const doubled = await snaptrude.core.math.vec3.scale(v, 2)\n * ```\n */\n abstract scale(v: Vec3Handle, scalar: number): PluginApiReturn<Vec3Handle>\n /**\n * Compute the dot product of two vectors.\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(1, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(0.5, 0.5, 0)\n * const d = await snaptrude.core.math.vec3.dot(a, b) // 0.5\n * ```\n */\n abstract dot(a: Vec3Handle, b: Vec3Handle): PluginApiReturn<number>\n /**\n * Compute the cross product `a × b` — the vector perpendicular to both.\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(1, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const perpendicular = await snaptrude.core.math.vec3.cross(a, b)\n * ```\n */\n abstract cross(a: Vec3Handle, b: Vec3Handle): PluginApiReturn<Vec3Handle>\n /**\n * Compute the Euclidean length (magnitude) of a vector.\n *\n * # Example\n * ```ts\n * const v = await snaptrude.core.math.vec3.new(3, 4, 0)\n * const len = await snaptrude.core.math.vec3.length(v) // 5\n * ```\n */\n abstract length(v: Vec3Handle): PluginApiReturn<number>\n /**\n * Compute the squared Euclidean length of a vector (avoids the sqrt).\n *\n * # Example\n * ```ts\n * const v = await snaptrude.core.math.vec3.new(3, 4, 0)\n * const sq = await snaptrude.core.math.vec3.lengthSquared(v) // 25\n * ```\n */\n abstract lengthSquared(v: Vec3Handle): PluginApiReturn<number>\n /**\n * Return the unit vector in the same direction (the zero vector if length is 0).\n *\n * # Example\n * ```ts\n * const v = await snaptrude.core.math.vec3.new(0, 0, 10)\n * const unit = await snaptrude.core.math.vec3.normalize(v) // (0, 0, 1)\n * ```\n */\n abstract normalize(v: Vec3Handle): PluginApiReturn<Vec3Handle>\n /**\n * Measure the straight-line (Euclidean) distance between two points.\n *\n * @examplePrompt What is the distance between these two points?\n * @examplePrompt Measure how far apart these two points are\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(3, 4, 0)\n * const dist = await snaptrude.core.math.vec3.distance(a, b) // 5\n * ```\n */\n abstract distance(a: Vec3Handle, b: Vec3Handle): PluginApiReturn<number>\n /**\n * Linearly interpolate between two vectors: `a + (b - a) * t`.\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const midpoint = await snaptrude.core.math.vec3.lerp(a, b, 0.5)\n * ```\n */\n abstract lerp(a: Vec3Handle, b: Vec3Handle, t: number): PluginApiReturn<Vec3Handle>\n /**\n * Negate a vector, reversing its direction.\n *\n * # Example\n * ```ts\n * const v = await snaptrude.core.math.vec3.new(1, -2, 3)\n * const reversed = await snaptrude.core.math.vec3.negate(v) // (-1, 2, -3)\n * ```\n */\n abstract negate(v: Vec3Handle): PluginApiReturn<Vec3Handle>\n /**\n * Test whether two vectors have exactly equal components.\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(1, 2, 3)\n * const b = await snaptrude.core.math.vec3.new(1, 2, 3)\n * const same = await snaptrude.core.math.vec3.equals(a, b) // true\n * ```\n */\n abstract equals(a: Vec3Handle, b: Vec3Handle): PluginApiReturn<boolean>\n /**\n * Test whether two vectors are equal within a tolerance `epsilon` (default `1e-6`).\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(1, 2, 3)\n * const b = await snaptrude.core.math.vec3.new(1.0004, 2, 3)\n * const close = await snaptrude.core.math.vec3.equalsApprox(a, b, 1e-3) // true\n * ```\n */\n abstract equalsApprox(\n a: Vec3Handle,\n b: Vec3Handle,\n epsilon?: number,\n ): PluginApiReturn<boolean>\n /**\n * Read the primitive `{ x, y, z }` components of a vector handle.\n *\n * # Example\n * ```ts\n * const v = await snaptrude.core.math.vec3.new(1, 2, 3)\n * const { x, y, z } = await snaptrude.core.math.vec3.components(v)\n * ```\n */\n abstract components(v: Vec3Handle): PluginApiReturn<Vec3Components>\n}\n","import { PluginApiReturn } from \"../../../types\"\nimport { Vec3Handle, QuatHandle, QuatComponents } from \"../../../handles\"\n\n/**\n * Quaternion operations (all-handle model, §11).\n *\n * Quaternions are opaque {@linkcode QuatHandle}s; every operation is a host call\n * returning a new handle. Read primitive components back with\n * {@linkcode PluginQuatApi.components}. Accessed via `snaptrude.core.math.quat`.\n */\nexport abstract class PluginQuatApi {\n constructor() {}\n\n /**\n * Create a quaternion from primitive components.\n *\n * # Example\n * ```ts\n * const q = await snaptrude.core.math.quat.new(0, 0, 0, 1)\n * const { x, y, z, w } = await snaptrude.core.math.quat.components(q)\n * ```\n */\n abstract new(x: number, y: number, z: number, w: number): PluginApiReturn<QuatHandle>\n /**\n * Return the identity quaternion (no rotation).\n *\n * # Example\n * ```ts\n * const noRotation = await snaptrude.core.math.quat.identity()\n * ```\n */\n abstract identity(): PluginApiReturn<QuatHandle>\n /**\n * Build a quaternion from a rotation axis and an angle in radians.\n *\n * # Example\n * ```ts\n * const axis = await snaptrude.core.math.vec3.new(0, 0, 1)\n * const quarterTurn = await snaptrude.core.math.quat.fromAxisAngle(axis, Math.PI / 2)\n * ```\n */\n abstract fromAxisAngle(axis: Vec3Handle, angle: number): PluginApiReturn<QuatHandle>\n /**\n * Build a quaternion from Euler angles in radians.\n *\n * # Example\n * ```ts\n * const q = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 2, 0)\n * ```\n */\n abstract fromEuler(x: number, y: number, z: number): PluginApiReturn<QuatHandle>\n /**\n * Compose two rotations with the Hamilton product `a * b` (apply `b` then `a`).\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 2, 0)\n * const b = await snaptrude.core.math.quat.fromEuler(Math.PI / 4, 0, 0)\n * const combined = await snaptrude.core.math.quat.multiply(a, b) // b first, then a\n * ```\n */\n abstract multiply(a: QuatHandle, b: QuatHandle): PluginApiReturn<QuatHandle>\n /**\n * Compute the conjugate of a quaternion (negated vector part).\n *\n * # Example\n * ```ts\n * const q = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 4, 0)\n * const conj = await snaptrude.core.math.quat.conjugate(q)\n * ```\n */\n abstract conjugate(q: QuatHandle): PluginApiReturn<QuatHandle>\n /**\n * Compute the magnitude (norm) of a quaternion.\n *\n * # Example\n * ```ts\n * const q = await snaptrude.core.math.quat.new(0, 0, 0, 1)\n * const len = await snaptrude.core.math.quat.length(q) // 1\n * ```\n */\n abstract length(q: QuatHandle): PluginApiReturn<number>\n /**\n * Normalize a quaternion to unit length.\n *\n * # Example\n * ```ts\n * const q = await snaptrude.core.math.quat.new(0, 0, 1, 1)\n * const unit = await snaptrude.core.math.quat.normalize(q)\n * ```\n */\n abstract normalize(q: QuatHandle): PluginApiReturn<QuatHandle>\n /**\n * Compute the inverse quaternion — the rotation that undoes `q`.\n *\n * # Example\n * ```ts\n * const q = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 2, 0)\n * const undo = await snaptrude.core.math.quat.inverse(q)\n * ```\n */\n abstract inverse(q: QuatHandle): PluginApiReturn<QuatHandle>\n /**\n * Decompose a quaternion into its rotation axis and angle (radians).\n *\n * # Example\n * ```ts\n * const q = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 3, 0)\n * const { axis, angle } = await snaptrude.core.math.quat.toAxisAngle(q)\n * const { x, y, z } = await snaptrude.core.math.vec3.components(axis)\n * ```\n */\n abstract toAxisAngle(q: QuatHandle): PluginApiReturn<{ axis: Vec3Handle; angle: number }>\n /**\n * Spherically interpolate (slerp) between two rotations by factor `t`.\n *\n * # Example\n * ```ts\n * const start = await snaptrude.core.math.quat.identity()\n * const end = await snaptrude.core.math.quat.fromEuler(0, Math.PI, 0)\n * const halfway = await snaptrude.core.math.quat.slerp(start, end, 0.5)\n * ```\n */\n abstract slerp(a: QuatHandle, b: QuatHandle, t: number): PluginApiReturn<QuatHandle>\n /**\n * Compute the dot product of two quaternions.\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.quat.identity()\n * const b = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 2, 0)\n * const d = await snaptrude.core.math.quat.dot(a, b)\n * ```\n */\n abstract dot(a: QuatHandle, b: QuatHandle): PluginApiReturn<number>\n /**\n * Test whether two quaternions have exactly equal components.\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.quat.new(0, 0, 0, 1)\n * const b = await snaptrude.core.math.quat.identity()\n * const same = await snaptrude.core.math.quat.equals(a, b) // true\n * ```\n */\n abstract equals(a: QuatHandle, b: QuatHandle): PluginApiReturn<boolean>\n /**\n * Test whether two quaternions are equal within a tolerance `epsilon` (default `1e-6`).\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 2, 0)\n * const b = await snaptrude.core.math.quat.fromEuler(0, 1.5711, 0)\n * const close = await snaptrude.core.math.quat.equalsApprox(a, b, 1e-3) // true\n * ```\n */\n abstract equalsApprox(\n a: QuatHandle,\n b: QuatHandle,\n epsilon?: number,\n ): PluginApiReturn<boolean>\n /**\n * Read the primitive `{ x, y, z, w }` components of a quaternion handle.\n *\n * # Example\n * ```ts\n * const q = await snaptrude.core.math.quat.fromEuler(0, Math.PI / 2, 0)\n * const { x, y, z, w } = await snaptrude.core.math.quat.components(q)\n * ```\n */\n abstract components(q: QuatHandle): PluginApiReturn<QuatComponents>\n}\n","import { PluginVec3Api } from \"./vec3\"\nimport { PluginQuatApi } from \"./quat\"\n\n/**\n * Math primitives for 3D vector and quaternion operations.\n *\n * - {@linkcode PluginMathApi.vec3} — 3D vector creation and arithmetic\n * - {@linkcode PluginMathApi.quat} — Quaternion creation and rotation operations\n */\nexport abstract class PluginMathApi {\n /** 3D vector operations. See {@linkcode PluginVec3Api}. */\n public abstract vec3: PluginVec3Api\n /** Quaternion operations. See {@linkcode PluginQuatApi}. */\n public abstract quat: PluginQuatApi\n\n constructor() {}\n}\n\nexport * from \"./vec3\"\nexport * from \"./quat\"\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport { Vec3Handle, LineHandle, ArcHandle, CircleHandle, CurveHandle, ProfileHandle, ContourHandle } from \"../../../../handles\"\n\n/**\n * Curve creation — construct new geometric curves from point handles (all-handle\n * model, §11).\n *\n * Each method takes point handles ({@linkcode Vec3Handle}) and returns an opaque\n * curve handle ({@linkcode LineHandle} or {@linkcode ArcHandle}) that you pass to\n * query, update, or entity-creation methods. Read geometry back as plain values\n * via the `snaptrude.core.geom.query.*` methods.\n *\n * Accessed via `snaptrude.core.geom.create`.\n */\nexport abstract class PluginGeomCreateApi {\n constructor() {}\n\n /**\n * Create a straight line segment between two point handles. Host API call —\n * returns a handle.\n *\n * @param startPoint Start point of the line segment\n * @param endPoint End point of the line segment\n * @returns The new line as a {@linkcode LineHandle}\n *\n * @examplePrompt Draw a line from point A to point B\n * @examplePrompt Draw a straight edge between these two points\n *\n * @example\n * ```ts\n * const line = snaptrude.core.geom.create.line(startPoint, endPoint)\n * ```\n */\n public abstract line(startPoint: Vec3Handle, endPoint: Vec3Handle): PluginApiReturn<LineHandle>\n\n /**\n * Create a circular arc from its start, end, centre, and axis point handles.\n * Host API call — returns a handle.\n *\n * @param startPoint Start point of the arc\n * @param endPoint End point of the arc\n * @param centrePoint Centre point of the arc\n * @param axis Axis direction of the arc\n * @returns The new arc as an {@linkcode ArcHandle}\n *\n * @examplePrompt Draw an arc between these two points around a centre\n * @examplePrompt Add a curved segment from A to B\n *\n * @example\n * ```ts\n * const arc = snaptrude.core.geom.create.arc(startPoint, endPoint, centrePoint, axis)\n * ```\n */\n public abstract arc(\n startPoint: Vec3Handle,\n endPoint: Vec3Handle,\n centrePoint: Vec3Handle,\n axis: Vec3Handle,\n ): PluginApiReturn<ArcHandle>\n\n /**\n * Create a circle from a centre point, an axis (plane normal), and a radius.\n * Host API call — returns a handle. A circle is a closed curve; read it back via\n * `snaptrude.core.geom.query.circle.*`.\n *\n * @param centrePoint Centre point of the circle\n * @param axis Axis direction (plane normal) of the circle\n * @param radius Radius of the circle\n * @returns The new circle as a {@linkcode CircleHandle}\n *\n * @examplePrompt Make a circle of radius 2 at this point\n * @examplePrompt Draw a circular outline 5m across\n *\n * @example\n * ```ts\n * const circle = snaptrude.core.geom.create.circle(centrePoint, axis, 2)\n * ```\n */\n public abstract circle(\n centrePoint: Vec3Handle,\n axis: Vec3Handle,\n radius: number,\n ): PluginApiReturn<CircleHandle>\n\n /**\n * Create a closed profile from an ordered list of point handles connected by\n * line segments (last auto-connected to first). Host API call — returns a handle.\n *\n * @param points Ordered vertex handles of the profile\n * @returns The new profile as a {@linkcode ProfileHandle}\n *\n * @examplePrompt Draw a closed polygon through these corner points\n * @examplePrompt Create an L-shaped outline from a list of points\n *\n * @example\n * ```ts\n * const profile = snaptrude.core.geom.create.profileFromLinePoints(points)\n * ```\n */\n public abstract profileFromLinePoints(points: Vec3Handle[]): PluginApiReturn<ProfileHandle>\n\n /**\n * Create a profile from an ordered list of curve handles forming a closed loop.\n * Host API call — returns a handle.\n *\n * @param curves Ordered curve handles forming a closed loop\n * @returns The new profile as a {@linkcode ProfileHandle}\n *\n * @examplePrompt Join these lines and arcs into one closed shape\n *\n * @example\n * ```ts\n * const profile = snaptrude.core.geom.create.profileFromCurves([line, arc])\n * ```\n */\n public abstract profileFromCurves(curves: CurveHandle[]): PluginApiReturn<ProfileHandle>\n\n /**\n * Create an axis-aligned **rectangle** profile (XZ plane) of `width` × `depth`,\n * centred at `center` (defaults to the origin). Host API call — returns a handle.\n *\n * Pair with `design.create.space` / `design.create.spaces` to author a rectangular\n * (box) space — there is no dedicated rectangular-space creator; build the profile\n * here, then extrude it.\n *\n * @param width Extent along X\n * @param depth Extent along Z\n * @param center Optional centre point (default origin)\n * @returns The new rectangle profile as a {@linkcode ProfileHandle}\n *\n * @examplePrompt Draw a 4m by 3m rectangle\n * @examplePrompt Make a rectangular outline for a room footprint\n *\n * @example\n * ```ts\n * const rect = snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = snaptrude.core.geom.create.contourFromProfile(rect)\n * const space = snaptrude.design.create.space(contour, 3)\n * ```\n */\n public abstract profileRect(\n width: number,\n depth: number,\n center?: Vec3Handle,\n ): PluginApiReturn<ProfileHandle>\n\n /**\n * Create a contour (an outer profile loop, no holes). Host API call — returns a handle.\n *\n * @param outer The outer boundary loop\n * @returns The new contour as a {@linkcode ContourHandle}\n * @example\n * ```ts\n * const contour = snaptrude.core.geom.create.contourFromProfile(outer)\n * ```\n */\n public abstract contourFromProfile(outer: ProfileHandle): PluginApiReturn<ContourHandle>\n\n /**\n * Create a contour from an outer profile plus zero or more inner profiles (holes).\n * Host API call — returns a handle.\n *\n * @param outer The outer boundary loop\n * @param holes Optional inner hole loops\n * @returns The new contour as a {@linkcode ContourHandle}\n *\n * @examplePrompt Make a shape with a hole in the middle\n * @examplePrompt Cut a courtyard opening out of this floor outline\n *\n * @example\n * ```ts\n * const contour = snaptrude.core.geom.create.contourFromProfiles(outer, [hole])\n * ```\n */\n public abstract contourFromProfiles(\n outer: ProfileHandle,\n holes?: ProfileHandle[],\n ): PluginApiReturn<ContourHandle>\n}\n\n/**\n * Arguments for {@linkcode PluginGeomCreateApi.line}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `startPoint` | {@linkcode Vec3Handle} | Start point of the line segment |\n * | `endPoint` | {@linkcode Vec3Handle} | End point of the line segment |\n */\nexport const PluginGeomCreateLineArgs = z.object({\n startPoint: Vec3Handle,\n endPoint: Vec3Handle,\n})\n\nexport type PluginGeomCreateLineArgs = z.infer<typeof PluginGeomCreateLineArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomCreateApi.arc}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `startPoint` | {@linkcode Vec3Handle} | Start point of the arc |\n * | `endPoint` | {@linkcode Vec3Handle} | End point of the arc |\n * | `centrePoint` | {@linkcode Vec3Handle} | Centre point of the arc |\n * | `axis` | {@linkcode Vec3Handle} | Axis direction of the arc |\n */\nexport const PluginGeomCreateArcArgs = z.object({\n startPoint: Vec3Handle,\n endPoint: Vec3Handle,\n centrePoint: Vec3Handle,\n axis: Vec3Handle,\n})\n\nexport type PluginGeomCreateArcArgs = z.infer<typeof PluginGeomCreateArcArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomCreateApi.circle}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `centrePoint` | {@linkcode Vec3Handle} | Centre point of the circle |\n * | `axis` | {@linkcode Vec3Handle} | Axis direction (plane normal) of the circle |\n * | `radius` | `number` | Radius of the circle |\n */\nexport const PluginGeomCreateCircleArgs = z.object({\n centrePoint: Vec3Handle,\n axis: Vec3Handle,\n radius: z.number(),\n})\n\nexport type PluginGeomCreateCircleArgs = z.infer<typeof PluginGeomCreateCircleArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomCreateApi.profileFromLinePoints}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `points` | {@linkcode Vec3Handle}`[]` | Ordered vertex handles of the profile |\n */\nexport const PluginGeomCreateProfileFromLinePointsArgs = z.object({\n points: z.array(Vec3Handle),\n})\n\nexport type PluginGeomCreateProfileFromLinePointsArgs = z.infer<\n typeof PluginGeomCreateProfileFromLinePointsArgs\n>\n\n/**\n * Arguments for {@linkcode PluginGeomCreateApi.profileFromCurves}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curves` | {@linkcode CurveHandle}`[]` | Ordered curve handles forming a closed loop |\n */\nexport const PluginGeomCreateProfileFromCurvesArgs = z.object({\n curves: z.array(CurveHandle),\n})\n\nexport type PluginGeomCreateProfileFromCurvesArgs = z.infer<\n typeof PluginGeomCreateProfileFromCurvesArgs\n>\n\n/**\n * Arguments for {@linkcode PluginGeomCreateApi.contourFromProfile}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `outer` | {@linkcode ProfileHandle} | The outer boundary loop |\n */\nexport const PluginGeomCreateContourFromProfileArgs = z.object({\n outer: ProfileHandle,\n})\n\nexport type PluginGeomCreateContourFromProfileArgs = z.infer<\n typeof PluginGeomCreateContourFromProfileArgs\n>\n\n/**\n * Arguments for {@linkcode PluginGeomCreateApi.contourFromProfiles}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `outer` | {@linkcode ProfileHandle} | The outer boundary loop |\n * | `holes` | {@linkcode ProfileHandle}`[]` | Optional inner hole loops |\n */\nexport const PluginGeomCreateContourFromProfilesArgs = z.object({\n outer: ProfileHandle,\n holes: z.array(ProfileHandle).optional(),\n})\n\nexport type PluginGeomCreateContourFromProfilesArgs = z.infer<\n typeof PluginGeomCreateContourFromProfilesArgs\n>\n","import * as z from \"zod\"\n\n/**\n * An opaque, kind-tagged reference to a host-side object that crosses the RPC\n * boundary by IDENTITY rather than by value. See `PLUGIN_API_EXPOSURE_HLD.md` §9.\n *\n * The phantom `__handle` brand makes a `Handle<\"profile\">` incompatible with a\n * `Handle<\"mass\">` at compile time. At runtime a handle is just a string of the\n * form `\"<kind>_<token>\"` (e.g. `\"profile_k3f9a2x\"`), so it is structured-clone\n * safe and engine-free — plugin-core never imports the engine type it points at.\n */\nexport type Handle<K extends string> = string & { readonly __handle: K }\n\n/**\n * A scene-entity handle. Backed by the host `Component.id` and resolved live via\n * the host scene index (StructureCollection) — never stored in the resource\n * registry. Stable across undo/redo and persistable across sessions (§9.2).\n */\nexport type EntityId<K extends string = string> = Handle<K>\n\n/** Resource handle: a host-resident, session-ephemeral geometry object (§9.2). */\nexport type ProfileHandle = Handle<\"profile\">\n\n/** Resource handle: a host-resident contour (outer profile + hole profiles). */\nexport type ContourHandle = Handle<\"contour\">\n\n/** Entity-handle example: a Mass / space scene object (Component.id). */\nexport type MassHandle = EntityId<\"mass\">\n\n/**\n * A scene BIM entity (wall, space, slab, floor, …). Backed by `Component.id` and\n * resolved live via the host scene index (StructureCollection) — never stored in\n * the resource registry. Stable across undo/redo and persistable (§9.2). This is\n * the canonical return handle for every `design.create.*` creator. The token is\n * the raw `Component.id` — NO `\"component_\"` prefix, so it round-trips with the\n * ids the host already hands out.\n */\nexport type ComponentHandle = EntityId<\"component\">\n\n/**\n * A material handle. Like {@linkcode ComponentHandle}/`CommentHandle` this is an\n * arena-free **entity-style** handle: the token IS the material's stable engine\n * name (`Material.name`/`.id`), resolved live via `scene.getMaterialByName`\n * host-side — no registry arena, no quota, no dispose, stable across undo/redo.\n * Project-scoped, not a scene entity.\n */\nexport type MaterialHandle = EntityId<\"material\">\n\n// ── Value-kind handles (all-handle model, §11) ──────────────────────────────\n// Under the all-handle decision every structured type is a handle. The only\n// non-handles crossing the boundary are JS primitives (number/string/boolean)\n// and enums — the irreducible construction/read leaves. Value handles are\n// immutable; math/geom operate on them via host RPC (no in-worker compute).\nexport type Vec3Handle = Handle<\"vec3\">\nexport type QuatHandle = Handle<\"quat\">\nexport type LineHandle = Handle<\"line\">\nexport type ArcHandle = Handle<\"arc\">\n/** A curve is a line or an arc — its handle is one of those kinds. */\nexport type CurveHandle = LineHandle | ArcHandle\n/**\n * A circle value handle. A circle is a CLOSED curve — it deliberately does NOT\n * join {@linkcode CurveHandle} (it has no stable start/end and would break the\n * shared curve read contract), so it carries its own kind and its own\n * `core.geom.query.circle` namespace (mirroring `query.arc`).\n */\nexport type CircleHandle = Handle<\"circle\">\n\n// ── BREP topology handles (geometry-kernel resource family, §2A.2.1) ─────────\n// Session-ephemeral, identity-deduped RESOURCE handles for the boundary-\n// representation topology graph. Read-only via `core.geom.query.{brep,face,edge,\n// halfedge,vertex}`; they go stale on undo/redo/re-topologize. Obtain a brep via\n// `design.query.geometry.getBrep`; every other topology handle is minted by\n// walking from a brep/face/edge/vertex handle already resolved off that brep.\nexport type BrepHandle = Handle<\"brep\">\nexport type FaceHandle = Handle<\"face\">\nexport type EdgeHandle = Handle<\"edge\">\n/** Half-edge kind token is all-lowercase `\"halfedge\"` per §6.1 (no camelCase namespaces). */\nexport type HalfEdgeHandle = Handle<\"halfedge\">\nexport type VertexHandle = Handle<\"vertex\">\n\n/**\n * Bare primitive records — how value-handle reads return their components\n * (§11.4). Curves have **no** by-value record: a curve crosses the boundary as a\n * {@linkcode CurveHandle} (line/arc), and its coordinates are read via the\n * `core.geom.query.curve` API. There is no `CurveData` under the all-handle model.\n */\nexport type Vec3Components = { x: number; y: number; z: number }\nexport type QuatComponents = { x: number; y: number; z: number; w: number }\n/** Axis-aligned bounding box, read as two primitive corner records. */\nexport type BBoxComponents = { min: Vec3Components; max: Vec3Components }\n\n/**\n * Build a Zod schema validating a handle of the given `kind` at the trust\n * boundary. It checks only the `\"<kind>_\"` prefix shape; existence, kind, and\n * ownership are enforced host-side by the HandleRegistry (§9.7). Keeping it to\n * the prefix is engine-free and avoids an existence oracle.\n */\nexport const handleSchema = <K extends string>(kind: K) =>\n z\n .string()\n .regex(new RegExp(`^${kind}_[A-Za-z0-9_-]+$`), `expected a \"${kind}\" handle`)\n .transform((s) => s as Handle<K>)\n\nexport const ProfileHandle = handleSchema(\"profile\")\nexport const ContourHandle = handleSchema(\"contour\")\nexport const MassHandle = handleSchema(\"mass\")\n\n/**\n * Entity handles are raw `Component.id` strings (no `\"<kind>_\"` prefix) — validated\n * only as a non-empty string, resolved live via the scene index host-side.\n */\nexport const ComponentHandle = z\n .string()\n .min(1)\n .transform((s) => s as ComponentHandle)\n\n/**\n * Material handles are the raw `Material.name` string (entity-style, no `\"<kind>_\"`\n * prefix) — validated only as non-empty, resolved live via `scene.getMaterialByName`.\n */\nexport const MaterialHandle = z\n .string()\n .min(1)\n .transform((s) => s as MaterialHandle)\n\n// Value-kind handle schemas (all-handle model, §11).\nexport const Vec3Handle = handleSchema(\"vec3\")\nexport const QuatHandle = handleSchema(\"quat\")\nexport const LineHandle = handleSchema(\"line\")\nexport const ArcHandle = handleSchema(\"arc\")\nexport const CurveHandle = z.union([LineHandle, ArcHandle])\nexport const CircleHandle = handleSchema(\"circle\")\n\n// BREP topology handle schemas (§2A.2.1). Prefix-shape validation only; existence,\n// kind, and ownership are enforced host-side by the HandleRegistry topology arena.\nexport const BrepHandle = handleSchema(\"brep\")\nexport const FaceHandle = handleSchema(\"face\")\nexport const EdgeHandle = handleSchema(\"edge\")\nexport const HalfEdgeHandle = handleSchema(\"halfedge\")\nexport const VertexHandle = handleSchema(\"vertex\")\nexport const Vec3Components = z.object({ x: z.number(), y: z.number(), z: z.number() })\nexport const QuatComponents = z.object({\n x: z.number(),\n y: z.number(),\n z: z.number(),\n w: z.number(),\n})\nexport const BBoxComponents = z.object({ min: Vec3Components, max: Vec3Components })\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport { Vec3Handle, CurveHandle, LineHandle, Vec3Components } from \"../../../../handles\"\n\n/**\n * Curve queries — read-only geometric questions about curves (lines and arcs)\n * and the relationships between two curves (all-handle model, §11).\n *\n * Every method takes opaque curve handles ({@linkcode CurveHandle}/{@linkcode LineHandle})\n * and point handles ({@linkcode Vec3Handle}) and returns plain values — points as\n * {@linkcode Vec3Components}, lengths/distances/parameters as `number`, predicates as\n * `boolean`. Relationship methods that produce a new curve return a\n * {@linkcode CurveHandle} (or `null` when there is no result). No query mutates its\n * inputs.\n *\n * Accessed via `snaptrude.core.geom.query.curve`.\n */\nexport abstract class PluginGeomQueryCurveApi {\n constructor() {}\n\n /**\n * Get the start point of a curve.\n * @param curve The curve to query\n * @returns The start point as {@linkcode Vec3Components}\n *\n * @examplePrompt Where does this wall edge start?\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const centerline = await snaptrude.design.query.geometry.getCenterline(wall)\n * if (centerline) {\n * const start = await snaptrude.core.geom.query.curve.getStartPoint(centerline)\n * console.log(start.x, start.y, start.z)\n * }\n * ```\n */\n public abstract getStartPoint(curve: CurveHandle): PluginApiReturn<Vec3Components>\n\n /**\n * Get the end point of a curve.\n * @param curve The curve to query\n * @returns The end point as {@linkcode Vec3Components}\n *\n * @examplePrompt Get the coordinates of the far end of this edge\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const end = await snaptrude.core.geom.query.curve.getEndPoint(line) // { x: 5, y: 0, z: 0 }\n * ```\n */\n public abstract getEndPoint(curve: CurveHandle): PluginApiReturn<Vec3Components>\n\n /**\n * Get the mid point of a curve.\n * @param curve The curve to query\n * @returns The mid point as {@linkcode Vec3Components}\n *\n * @examplePrompt Find the midpoint of this wall edge\n * @examplePrompt Where is the centre of this boundary line?\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const centerline = await snaptrude.design.query.geometry.getCenterline(wall)\n * if (centerline) {\n * const mid = await snaptrude.core.geom.query.curve.getMidPoint(centerline)\n * console.log(mid.x, mid.y, mid.z)\n * }\n * ```\n */\n public abstract getMidPoint(curve: CurveHandle): PluginApiReturn<Vec3Components>\n\n /**\n * Get the arc-length of a curve.\n * @param curve The curve to query\n * @returns The curve length as a `number`\n *\n * @examplePrompt How long is this wall edge?\n * @examplePrompt Measure the length of this curved boundary\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const centerline = await snaptrude.design.query.geometry.getCenterline(wall)\n * if (centerline) {\n * const length = await snaptrude.core.geom.query.curve.getLength(centerline)\n * }\n * ```\n */\n public abstract getLength(curve: CurveHandle): PluginApiReturn<number>\n\n /**\n * Get the straight-line chord length between a curve's endpoints.\n * @param curve The curve to query\n * @returns The chord length as a `number`\n *\n * @examplePrompt What is the straight-line distance between the two ends of this arc?\n *\n * # Example\n * ```ts\n * const start = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const end = await snaptrude.core.math.vec3.new(-5, 0, 0)\n * const centre = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const axis = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const arc = await snaptrude.core.geom.create.arc(start, end, centre, axis)\n * const chord = await snaptrude.core.geom.query.curve.getChordLength(arc) // 10 (getLength gives the arc length)\n * ```\n */\n public abstract getChordLength(curve: CurveHandle): PluginApiReturn<number>\n\n /**\n * Get the unit tangent vector of a curve at a point on it.\n * @param curve The curve to query\n * @param point Point on the curve\n * @returns The tangent vector as {@linkcode Vec3Components}\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(3, 0, 4)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const tangent = await snaptrude.core.geom.query.curve.getTangent(line, a) // { x: 0.6, y: 0, z: 0.8 }\n * ```\n */\n public abstract getTangent(\n curve: CurveHandle,\n point: Vec3Handle,\n ): PluginApiReturn<Vec3Components>\n\n /**\n * Get the unit normal vector of a curve at a point on it.\n * @param curve The curve to query\n * @param point Point on the curve\n * @returns The normal vector as {@linkcode Vec3Components}\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const normal = await snaptrude.core.geom.query.curve.getNormal(line, a)\n * ```\n */\n public abstract getNormal(\n curve: CurveHandle,\n point: Vec3Handle,\n ): PluginApiReturn<Vec3Components>\n\n /**\n * Get the point on a curve nearest to an arbitrary point.\n * @param curve The curve to query\n * @param point The reference point\n * @returns The nearest point on the curve as {@linkcode Vec3Components}\n *\n * @examplePrompt Find the point on this edge closest to the column\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const centerline = await snaptrude.design.query.geometry.getCenterline(wall)\n * const reference = await snaptrude.core.math.vec3.new(2, 0, 3)\n * if (centerline) {\n * const nearest = await snaptrude.core.geom.query.curve.getNearestPoint(centerline, reference)\n * }\n * ```\n */\n public abstract getNearestPoint(\n curve: CurveHandle,\n point: Vec3Handle,\n ): PluginApiReturn<Vec3Components>\n\n /**\n * Project a point onto a curve.\n * @param curve The curve to project onto\n * @param point The point to project\n * @returns The projected point as {@linkcode Vec3Components}\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const point = await snaptrude.core.math.vec3.new(3, 0, 4)\n * const projected = await snaptrude.core.geom.query.curve.getProjection(line, point) // { x: 3, y: 0, z: 0 }\n * ```\n */\n public abstract getProjection(\n curve: CurveHandle,\n point: Vec3Handle,\n ): PluginApiReturn<Vec3Components>\n\n /**\n * Get the point at a given distance along a curve from a reference point.\n * @param curve The curve to query\n * @param referencePoint Point on the curve to measure from\n * @param distance Distance along the curve from the reference point\n * @param forward Optional direction along the curve (defaults to `true`)\n * @returns The resulting point as {@linkcode Vec3Components}\n *\n * @examplePrompt Find the point 2 metres along this edge from the corner\n * @examplePrompt Mark a spot 900mm from the start of the wall edge\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const p = await snaptrude.core.geom.query.curve.getPointAtDistance(line, a, 2) // { x: 2, y: 0, z: 0 }\n * const q = await snaptrude.core.geom.query.curve.getPointAtDistance(line, b, 2, false) // measured backwards from the end\n * ```\n */\n public abstract getPointAtDistance(\n curve: CurveHandle,\n referencePoint: Vec3Handle,\n distance: number,\n forward?: boolean,\n ): PluginApiReturn<Vec3Components>\n\n /**\n * Get the curve parameter corresponding to a point on the curve.\n * @param curve The curve to query\n * @param point Point on the curve\n * @returns The parameter as a `number`\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(8, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const t = await snaptrude.core.geom.query.curve.getParameterAtPoint(line, b)\n * ```\n */\n public abstract getParameterAtPoint(\n curve: CurveHandle,\n point: Vec3Handle,\n ): PluginApiReturn<number>\n\n /**\n * Get the curvature of a curve at a point on it.\n * @param curve The curve to query\n * @param point Point on the curve\n * @returns The curvature as a `number`\n *\n * # Example\n * ```ts\n * const start = await snaptrude.core.math.vec3.new(2, 0, 0)\n * const end = await snaptrude.core.math.vec3.new(-2, 0, 0)\n * const centre = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const axis = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const arc = await snaptrude.core.geom.create.arc(start, end, centre, axis)\n * const k = await snaptrude.core.geom.query.curve.getCurvature(arc, start) // 0.5 (1 / radius)\n * ```\n */\n public abstract getCurvature(\n curve: CurveHandle,\n point: Vec3Handle,\n ): PluginApiReturn<number>\n\n /**\n * Get the shortest distance from an arbitrary point to a curve.\n * @param curve The curve to query\n * @param point The point to measure from\n * @returns The distance as a `number`\n *\n * @examplePrompt How far is this column from the wall edge?\n * @examplePrompt What is the shortest distance from this point to the boundary line?\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const centerline = await snaptrude.design.query.geometry.getCenterline(wall)\n * const point = await snaptrude.core.math.vec3.new(2, 0, 3)\n * if (centerline) {\n * const distance = await snaptrude.core.geom.query.curve.getDistanceToPoint(centerline, point)\n * }\n * ```\n */\n public abstract getDistanceToPoint(\n curve: CurveHandle,\n point: Vec3Handle,\n ): PluginApiReturn<number>\n\n /**\n * Get the arc-length distance along a curve between two points on it.\n * @param curve The curve to query\n * @param pointA First point on the curve\n * @param pointB Second point on the curve\n * @returns The distance along the curve as a `number`\n *\n * @examplePrompt How far apart are these two points measured along the curved wall?\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const mid = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const d = await snaptrude.core.geom.query.curve.getDistanceAlong(line, a, mid) // 5\n * ```\n */\n public abstract getDistanceAlong(\n curve: CurveHandle,\n pointA: Vec3Handle,\n pointB: Vec3Handle,\n ): PluginApiReturn<number>\n\n /**\n * List sampled points along a curve.\n * @param curve The curve to sample\n * @param resolution Optional number of samples for arcs (defaults to `20`; ignored for lines)\n * @returns The sampled points as {@linkcode Vec3Components}`[]`\n *\n * # Example\n * ```ts\n * const start = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const end = await snaptrude.core.math.vec3.new(0, 0, 5)\n * const centre = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const axis = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const arc = await snaptrude.core.geom.create.arc(start, end, centre, axis)\n * const points = await snaptrude.core.geom.query.curve.listPoints(arc, 40)\n * for (const p of points) console.log(p.x, p.y, p.z)\n * ```\n */\n public abstract listPoints(\n curve: CurveHandle,\n resolution?: number,\n ): PluginApiReturn<Vec3Components[]>\n\n /**\n * List the points produced by subdividing a curve into equal segments.\n * @param curve The curve to subdivide\n * @param segments Number of equal segments to divide the curve into\n * @returns The subdivision points as {@linkcode Vec3Components}`[]`\n *\n * @examplePrompt Divide this edge into 5 equal segments\n * @examplePrompt Split the wall line into equal parts for placing columns\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const centerline = await snaptrude.design.query.geometry.getCenterline(wall)\n * if (centerline) {\n * const points = await snaptrude.core.geom.query.curve.listSubdivisions(centerline, 5)\n * }\n * ```\n */\n public abstract listSubdivisions(\n curve: CurveHandle,\n segments: number,\n ): PluginApiReturn<Vec3Components[]>\n\n /**\n * Test whether a curve is a straight line.\n * @param curve The curve to query\n * @returns `true` if the curve is linear, otherwise `false`\n *\n * @examplePrompt Is this edge straight or curved?\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const centerline = await snaptrude.design.query.geometry.getCenterline(wall)\n * if (centerline) {\n * const straight = await snaptrude.core.geom.query.curve.isLinear(centerline)\n * }\n * ```\n */\n public abstract isLinear(curve: CurveHandle): PluginApiReturn<boolean>\n\n /**\n * Test whether a point lies on a curve within an optional threshold.\n * @param curve The curve to query\n * @param point The point to test\n * @param threshold Optional distance tolerance (defaults to the engine default)\n * @returns `true` if the point is on the curve, otherwise `false`\n *\n * @examplePrompt Check whether this point lies on the wall edge\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const point = await snaptrude.core.math.vec3.new(5, 0, 0.005)\n * const on = await snaptrude.core.geom.query.curve.isOnCurve(line, point, 0.01) // true within tolerance\n * ```\n */\n public abstract isOnCurve(\n curve: CurveHandle,\n point: Vec3Handle,\n threshold?: number,\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether a curve contains a point, optionally including its endpoints.\n * @param curve The curve to query\n * @param point The point to test\n * @param includeEndPoints Optional flag to count endpoints as contained (defaults to `true`)\n * @returns `true` if the curve contains the point, otherwise `false`\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const atEnd = await snaptrude.core.geom.query.curve.hasPoint(line, b) // true (endpoints count by default)\n * const interiorOnly = await snaptrude.core.geom.query.curve.hasPoint(line, b, false) // false\n * ```\n */\n public abstract hasPoint(\n curve: CurveHandle,\n point: Vec3Handle,\n includeEndPoints?: boolean,\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether two curves are geometrically equal.\n * @param curveA First curve\n * @param curveB Second curve\n * @returns `true` if the curves are equal, otherwise `false`\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const lineA = await snaptrude.core.geom.create.line(a, b)\n * const lineB = await snaptrude.core.geom.create.line(a, b)\n * const same = await snaptrude.core.geom.query.curve.isEqual(lineA, lineB) // true\n * ```\n */\n public abstract isEqual(\n curveA: CurveHandle,\n curveB: CurveHandle,\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether two curves overlap (share a collinear/concentric span), optionally including their endpoints.\n * @param curveA First curve\n * @param curveB Second curve\n * @param includeEndPoints Optional flag to count endpoint contact as overlap (defaults to `false`)\n * @returns `true` if the curves overlap, otherwise `false`\n *\n * @examplePrompt Do these two wall edges overlap?\n *\n * # Example\n * ```ts\n * const p0 = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const p5 = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const p10 = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const p15 = await snaptrude.core.math.vec3.new(15, 0, 0)\n * const lineA = await snaptrude.core.geom.create.line(p0, p10)\n * const lineB = await snaptrude.core.geom.create.line(p5, p15)\n * const overlaps = await snaptrude.core.geom.query.curve.isOverlapping(lineA, lineB) // true (share the 5..10 span)\n * ```\n */\n public abstract isOverlapping(\n curveA: CurveHandle,\n curveB: CurveHandle,\n includeEndPoints?: boolean,\n ): PluginApiReturn<boolean>\n\n /**\n * Get the common (overlapping) part of two curves.\n * @param curveA First curve\n * @param curveB Second curve\n * @returns The common part as a {@linkcode CurveHandle}, or `null` if there is none\n *\n * @examplePrompt Get the shared segment where these two edges overlap\n *\n * # Example\n * ```ts\n * const p0 = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const p5 = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const p10 = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const p15 = await snaptrude.core.math.vec3.new(15, 0, 0)\n * const lineA = await snaptrude.core.geom.create.line(p0, p10)\n * const lineB = await snaptrude.core.geom.create.line(p5, p15)\n * const common = await snaptrude.core.geom.query.curve.getCommonPart(lineA, lineB)\n * if (common) {\n * const length = await snaptrude.core.geom.query.curve.getLength(common) // 5\n * }\n * ```\n */\n public abstract getCommonPart(\n curveA: CurveHandle,\n curveB: CurveHandle,\n ): PluginApiReturn<CurveHandle | null>\n\n /**\n * List the intersection points between two curves.\n * @param curveA First curve\n * @param curveB Second curve\n * @param boundedA Optional flag to bound intersections to `curveA`'s extent (defaults to `true`)\n * @param boundedB Optional flag to bound intersections to `curveB`'s extent (defaults to `true`)\n * @returns The intersection points as {@linkcode Vec3Components}`[]`\n *\n * @examplePrompt Where do these two lines cross?\n * @examplePrompt Find the intersection points of these two gridlines\n *\n * # Example\n * ```ts\n * const a1 = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const a2 = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const b1 = await snaptrude.core.math.vec3.new(5, 0, -5)\n * const b2 = await snaptrude.core.math.vec3.new(5, 0, 5)\n * const lineA = await snaptrude.core.geom.create.line(a1, a2)\n * const lineB = await snaptrude.core.geom.create.line(b1, b2)\n * const points = await snaptrude.core.geom.query.curve.listIntersections(lineA, lineB) // [{ x: 5, y: 0, z: 0 }]\n * const unbounded = await snaptrude.core.geom.query.curve.listIntersections(lineA, lineB, false, false) // treat both as infinite\n * ```\n */\n public abstract listIntersections(\n curveA: CurveHandle,\n curveB: CurveHandle,\n boundedA?: boolean,\n boundedB?: boolean,\n ): PluginApiReturn<Vec3Components[]>\n\n /**\n * Merge two curves into a single curve when they are mergeable.\n * @param curveA First curve\n * @param curveB Second curve\n * @returns The merged curve as a {@linkcode CurveHandle}, or `null` if they cannot be merged\n *\n * @examplePrompt Merge these two line segments into a single line\n *\n * # Example\n * ```ts\n * const p0 = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const p5 = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const p10 = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const lineA = await snaptrude.core.geom.create.line(p0, p5)\n * const lineB = await snaptrude.core.geom.create.line(p5, p10)\n * const merged = await snaptrude.core.geom.query.curve.getMergedCurve(lineA, lineB)\n * if (merged) {\n * const length = await snaptrude.core.geom.query.curve.getLength(merged) // 10\n * }\n * ```\n */\n public abstract getMergedCurve(\n curveA: CurveHandle,\n curveB: CurveHandle,\n ): PluginApiReturn<CurveHandle | null>\n\n /**\n * Test whether two curves are continuous (share an endpoint without a gap).\n * @param curveA First curve\n * @param curveB Second curve\n * @returns `true` if the curves are continuous, otherwise `false`\n *\n * @examplePrompt Do these two edges connect end to end without a gap?\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const c = await snaptrude.core.math.vec3.new(5, 0, 5)\n * const lineA = await snaptrude.core.geom.create.line(a, b)\n * const lineB = await snaptrude.core.geom.create.line(b, c)\n * const connected = await snaptrude.core.geom.query.curve.isContinuous(lineA, lineB) // true\n * ```\n */\n public abstract isContinuous(\n curveA: CurveHandle,\n curveB: CurveHandle,\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether two lines are parallel within an optional tolerance.\n * @param lineA First line\n * @param lineB Second line\n * @param tolerance Optional angular tolerance (defaults to the engine default)\n * @returns `true` if the lines are parallel, otherwise `false`\n *\n * @examplePrompt Are these two walls parallel?\n * @examplePrompt Check if these gridlines run parallel to each other\n *\n * # Example\n * ```ts\n * const a1 = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const a2 = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const b1 = await snaptrude.core.math.vec3.new(0, 0, 3)\n * const b2 = await snaptrude.core.math.vec3.new(10, 0, 3)\n * const lineA = await snaptrude.core.geom.create.line(a1, a2)\n * const lineB = await snaptrude.core.geom.create.line(b1, b2)\n * const parallel = await snaptrude.core.geom.query.curve.isParallel(lineA, lineB) // true\n * ```\n */\n public abstract isParallel(\n lineA: LineHandle,\n lineB: LineHandle,\n tolerance?: number,\n ): PluginApiReturn<boolean>\n\n /**\n * Get the shortest gap between two curves, optionally including their endpoints.\n * @param curveA First curve\n * @param curveB Second curve\n * @param includeEndPoints Optional flag to include endpoints when measuring (defaults to `false`)\n * @returns The shortest gap as a `number`\n *\n * @examplePrompt What is the gap between these two wall edges?\n * @examplePrompt How close do these two curves get to each other?\n *\n * # Example\n * ```ts\n * const a1 = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const a2 = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const b1 = await snaptrude.core.math.vec3.new(0, 0, 2)\n * const b2 = await snaptrude.core.math.vec3.new(5, 0, 2)\n * const curveA = await snaptrude.core.geom.create.line(a1, a2)\n * const curveB = await snaptrude.core.geom.create.line(b1, b2)\n * const gap = await snaptrude.core.geom.query.curve.getShortestGap(curveA, curveB) // 2\n * ```\n */\n public abstract getShortestGap(\n curveA: CurveHandle,\n curveB: CurveHandle,\n includeEndPoints?: boolean,\n ): PluginApiReturn<number>\n\n /**\n * Get the perpendicular distance between two parallel lines.\n * @param lineA First line\n * @param lineB Second line\n * @returns The distance between the lines as a `number`\n *\n * @examplePrompt How far apart are these two parallel walls?\n * @examplePrompt Measure the spacing between these two gridlines\n *\n * # Example\n * ```ts\n * const a1 = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const a2 = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const b1 = await snaptrude.core.math.vec3.new(0, 0, 4)\n * const b2 = await snaptrude.core.math.vec3.new(10, 0, 4)\n * const lineA = await snaptrude.core.geom.create.line(a1, a2)\n * const lineB = await snaptrude.core.geom.create.line(b1, b2)\n * const spacing = await snaptrude.core.geom.query.curve.getDistanceBetween(lineA, lineB) // 4\n * ```\n */\n public abstract getDistanceBetween(\n lineA: LineHandle,\n lineB: LineHandle,\n ): PluginApiReturn<number>\n}\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getStartPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n */\nexport const PluginGeomQueryCurveGetStartPointArgs = z.object({\n curve: CurveHandle,\n})\n\nexport type PluginGeomQueryCurveGetStartPointArgs = z.infer<typeof PluginGeomQueryCurveGetStartPointArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getEndPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n */\nexport const PluginGeomQueryCurveGetEndPointArgs = z.object({\n curve: CurveHandle,\n})\n\nexport type PluginGeomQueryCurveGetEndPointArgs = z.infer<typeof PluginGeomQueryCurveGetEndPointArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getMidPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n */\nexport const PluginGeomQueryCurveGetMidPointArgs = z.object({\n curve: CurveHandle,\n})\n\nexport type PluginGeomQueryCurveGetMidPointArgs = z.infer<typeof PluginGeomQueryCurveGetMidPointArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getLength}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n */\nexport const PluginGeomQueryCurveGetLengthArgs = z.object({\n curve: CurveHandle,\n})\n\nexport type PluginGeomQueryCurveGetLengthArgs = z.infer<typeof PluginGeomQueryCurveGetLengthArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getChordLength}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n */\nexport const PluginGeomQueryCurveGetChordLengthArgs = z.object({\n curve: CurveHandle,\n})\n\nexport type PluginGeomQueryCurveGetChordLengthArgs = z.infer<typeof PluginGeomQueryCurveGetChordLengthArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getTangent}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n * | `point` | {@linkcode Vec3Handle} | Point on the curve |\n */\nexport const PluginGeomQueryCurveGetTangentArgs = z.object({\n curve: CurveHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryCurveGetTangentArgs = z.infer<typeof PluginGeomQueryCurveGetTangentArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getNormal}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n * | `point` | {@linkcode Vec3Handle} | Point on the curve |\n */\nexport const PluginGeomQueryCurveGetNormalArgs = z.object({\n curve: CurveHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryCurveGetNormalArgs = z.infer<typeof PluginGeomQueryCurveGetNormalArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getNearestPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n * | `point` | {@linkcode Vec3Handle} | The reference point |\n */\nexport const PluginGeomQueryCurveGetNearestPointArgs = z.object({\n curve: CurveHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryCurveGetNearestPointArgs = z.infer<typeof PluginGeomQueryCurveGetNearestPointArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getProjection}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to project onto |\n * | `point` | {@linkcode Vec3Handle} | The point to project |\n */\nexport const PluginGeomQueryCurveGetProjectionArgs = z.object({\n curve: CurveHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryCurveGetProjectionArgs = z.infer<typeof PluginGeomQueryCurveGetProjectionArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getPointAtDistance}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n * | `referencePoint` | {@linkcode Vec3Handle} | Point on the curve to measure from |\n * | `distance` | `number` | Distance along the curve from the reference point |\n * | `forward` | `boolean` | Optional direction along the curve (defaults to `true`) |\n */\nexport const PluginGeomQueryCurveGetPointAtDistanceArgs = z.object({\n curve: CurveHandle,\n referencePoint: Vec3Handle,\n distance: z.number(),\n forward: z.boolean().optional(),\n})\n\nexport type PluginGeomQueryCurveGetPointAtDistanceArgs = z.infer<typeof PluginGeomQueryCurveGetPointAtDistanceArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getParameterAtPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n * | `point` | {@linkcode Vec3Handle} | Point on the curve |\n */\nexport const PluginGeomQueryCurveGetParameterAtPointArgs = z.object({\n curve: CurveHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryCurveGetParameterAtPointArgs = z.infer<typeof PluginGeomQueryCurveGetParameterAtPointArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getCurvature}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n * | `point` | {@linkcode Vec3Handle} | Point on the curve |\n */\nexport const PluginGeomQueryCurveGetCurvatureArgs = z.object({\n curve: CurveHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryCurveGetCurvatureArgs = z.infer<typeof PluginGeomQueryCurveGetCurvatureArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getDistanceToPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n * | `point` | {@linkcode Vec3Handle} | The point to measure from |\n */\nexport const PluginGeomQueryCurveGetDistanceToPointArgs = z.object({\n curve: CurveHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryCurveGetDistanceToPointArgs = z.infer<typeof PluginGeomQueryCurveGetDistanceToPointArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getDistanceAlong}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n * | `pointA` | {@linkcode Vec3Handle} | First point on the curve |\n * | `pointB` | {@linkcode Vec3Handle} | Second point on the curve |\n */\nexport const PluginGeomQueryCurveGetDistanceAlongArgs = z.object({\n curve: CurveHandle,\n pointA: Vec3Handle,\n pointB: Vec3Handle,\n})\n\nexport type PluginGeomQueryCurveGetDistanceAlongArgs = z.infer<typeof PluginGeomQueryCurveGetDistanceAlongArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.listPoints}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to sample |\n * | `resolution` | `number` | Optional number of samples for arcs (defaults to `20`; ignored for lines) |\n */\nexport const PluginGeomQueryCurveListPointsArgs = z.object({\n curve: CurveHandle,\n resolution: z.number().optional(),\n})\n\nexport type PluginGeomQueryCurveListPointsArgs = z.infer<typeof PluginGeomQueryCurveListPointsArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.listSubdivisions}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to subdivide |\n * | `segments` | `number` | Number of equal segments to divide the curve into |\n */\nexport const PluginGeomQueryCurveListSubdivisionsArgs = z.object({\n curve: CurveHandle,\n segments: z.number(),\n})\n\nexport type PluginGeomQueryCurveListSubdivisionsArgs = z.infer<typeof PluginGeomQueryCurveListSubdivisionsArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.isLinear}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n */\nexport const PluginGeomQueryCurveIsLinearArgs = z.object({\n curve: CurveHandle,\n})\n\nexport type PluginGeomQueryCurveIsLinearArgs = z.infer<typeof PluginGeomQueryCurveIsLinearArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.isOnCurve}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n * | `point` | {@linkcode Vec3Handle} | The point to test |\n * | `threshold` | `number` | Optional distance tolerance (defaults to the engine default) |\n */\nexport const PluginGeomQueryCurveIsOnCurveArgs = z.object({\n curve: CurveHandle,\n point: Vec3Handle,\n threshold: z.number().optional(),\n})\n\nexport type PluginGeomQueryCurveIsOnCurveArgs = z.infer<typeof PluginGeomQueryCurveIsOnCurveArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.hasPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to query |\n * | `point` | {@linkcode Vec3Handle} | The point to test |\n * | `includeEndPoints` | `boolean` | Optional flag to count endpoints as contained (defaults to `true`) |\n */\nexport const PluginGeomQueryCurveHasPointArgs = z.object({\n curve: CurveHandle,\n point: Vec3Handle,\n includeEndPoints: z.boolean().optional(),\n})\n\nexport type PluginGeomQueryCurveHasPointArgs = z.infer<typeof PluginGeomQueryCurveHasPointArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.isEqual}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curveA` | {@linkcode CurveHandle} | First curve |\n * | `curveB` | {@linkcode CurveHandle} | Second curve |\n */\nexport const PluginGeomQueryCurveIsEqualArgs = z.object({\n curveA: CurveHandle,\n curveB: CurveHandle,\n})\n\nexport type PluginGeomQueryCurveIsEqualArgs = z.infer<typeof PluginGeomQueryCurveIsEqualArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.isOverlapping}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curveA` | {@linkcode CurveHandle} | First curve |\n * | `curveB` | {@linkcode CurveHandle} | Second curve |\n * | `includeEndPoints` | `boolean` | Optional flag to count endpoint contact as overlap (defaults to `false`) |\n */\nexport const PluginGeomQueryCurveIsOverlappingArgs = z.object({\n curveA: CurveHandle,\n curveB: CurveHandle,\n includeEndPoints: z.boolean().optional(),\n})\n\nexport type PluginGeomQueryCurveIsOverlappingArgs = z.infer<typeof PluginGeomQueryCurveIsOverlappingArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getCommonPart}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curveA` | {@linkcode CurveHandle} | First curve |\n * | `curveB` | {@linkcode CurveHandle} | Second curve |\n */\nexport const PluginGeomQueryCurveGetCommonPartArgs = z.object({\n curveA: CurveHandle,\n curveB: CurveHandle,\n})\n\nexport type PluginGeomQueryCurveGetCommonPartArgs = z.infer<typeof PluginGeomQueryCurveGetCommonPartArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.listIntersections}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curveA` | {@linkcode CurveHandle} | First curve |\n * | `curveB` | {@linkcode CurveHandle} | Second curve |\n * | `boundedA` | `boolean` | Optional flag to bound intersections to `curveA`'s extent (defaults to `true`) |\n * | `boundedB` | `boolean` | Optional flag to bound intersections to `curveB`'s extent (defaults to `true`) |\n */\nexport const PluginGeomQueryCurveListIntersectionsArgs = z.object({\n curveA: CurveHandle,\n curveB: CurveHandle,\n boundedA: z.boolean().optional(),\n boundedB: z.boolean().optional(),\n})\n\nexport type PluginGeomQueryCurveListIntersectionsArgs = z.infer<typeof PluginGeomQueryCurveListIntersectionsArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getMergedCurve}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curveA` | {@linkcode CurveHandle} | First curve |\n * | `curveB` | {@linkcode CurveHandle} | Second curve |\n */\nexport const PluginGeomQueryCurveGetMergedCurveArgs = z.object({\n curveA: CurveHandle,\n curveB: CurveHandle,\n})\n\nexport type PluginGeomQueryCurveGetMergedCurveArgs = z.infer<typeof PluginGeomQueryCurveGetMergedCurveArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.isContinuous}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curveA` | {@linkcode CurveHandle} | First curve |\n * | `curveB` | {@linkcode CurveHandle} | Second curve |\n */\nexport const PluginGeomQueryCurveIsContinuousArgs = z.object({\n curveA: CurveHandle,\n curveB: CurveHandle,\n})\n\nexport type PluginGeomQueryCurveIsContinuousArgs = z.infer<typeof PluginGeomQueryCurveIsContinuousArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.isParallel}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `lineA` | {@linkcode LineHandle} | First line |\n * | `lineB` | {@linkcode LineHandle} | Second line |\n * | `tolerance` | `number` | Optional angular tolerance (defaults to the engine default) |\n */\nexport const PluginGeomQueryCurveIsParallelArgs = z.object({\n lineA: LineHandle,\n lineB: LineHandle,\n tolerance: z.number().optional(),\n})\n\nexport type PluginGeomQueryCurveIsParallelArgs = z.infer<typeof PluginGeomQueryCurveIsParallelArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getShortestGap}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curveA` | {@linkcode CurveHandle} | First curve |\n * | `curveB` | {@linkcode CurveHandle} | Second curve |\n * | `includeEndPoints` | `boolean` | Optional flag to include endpoints when measuring (defaults to `false`) |\n */\nexport const PluginGeomQueryCurveGetShortestGapArgs = z.object({\n curveA: CurveHandle,\n curveB: CurveHandle,\n includeEndPoints: z.boolean().optional(),\n})\n\nexport type PluginGeomQueryCurveGetShortestGapArgs = z.infer<typeof PluginGeomQueryCurveGetShortestGapArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCurveApi.getDistanceBetween}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `lineA` | {@linkcode LineHandle} | First line |\n * | `lineB` | {@linkcode LineHandle} | Second line |\n */\nexport const PluginGeomQueryCurveGetDistanceBetweenArgs = z.object({\n lineA: LineHandle,\n lineB: LineHandle,\n})\n\nexport type PluginGeomQueryCurveGetDistanceBetweenArgs = z.infer<typeof PluginGeomQueryCurveGetDistanceBetweenArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport { ArcHandle, Vec3Components } from \"../../../../handles\"\n\n/**\n * Arc-specific geometry queries — read circular-arc properties as plain values.\n *\n * Every method takes an opaque {@linkcode ArcHandle} and returns plain values\n * (numbers or {@linkcode Vec3Components}), never a handle. Use these to inspect\n * the radius, centre, axis, sweep angle, and validity of an arc handle obtained\n * from {@linkcode PluginGeomCreateApi.arc} or another query.\n *\n * Accessed via `snaptrude.core.geom.query.arc`.\n */\nexport abstract class PluginGeomQueryArcApi {\n constructor() {}\n\n /**\n * Read the radius of an arc.\n *\n * @param arc The arc to query\n * @returns The arc radius as a `number`\n *\n * @examplePrompt What is the radius of this curved wall segment?\n * @examplePrompt Measure the radius of the selected arc\n *\n * # Example\n * ```ts\n * const start = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const end = await snaptrude.core.math.vec3.new(0, 0, 5)\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const arc = await snaptrude.core.geom.create.arc(start, end, origin, up)\n * const radius = await snaptrude.core.geom.query.arc.getRadius(arc)\n * ```\n */\n public abstract getRadius(arc: ArcHandle): PluginApiReturn<number>\n\n /**\n * Read the centre point of an arc.\n *\n * @param arc The arc to query\n * @returns The arc centre as {@linkcode Vec3Components}\n *\n * @examplePrompt Where is the centre of this arc?\n * @examplePrompt Find the center point of the curved wall\n *\n * # Example\n * ```ts\n * const start = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const end = await snaptrude.core.math.vec3.new(0, 0, 5)\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const arc = await snaptrude.core.geom.create.arc(start, end, origin, up)\n * const centre = await snaptrude.core.geom.query.arc.getCentre(arc)\n * console.log(centre.x, centre.y, centre.z)\n * ```\n */\n public abstract getCentre(arc: ArcHandle): PluginApiReturn<Vec3Components>\n\n /**\n * Read the rotation axis of an arc.\n *\n * @param arc The arc to query\n * @returns The arc axis as {@linkcode Vec3Components}\n *\n * # Example\n * ```ts\n * const start = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const end = await snaptrude.core.math.vec3.new(0, 0, 5)\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const arc = await snaptrude.core.geom.create.arc(start, end, origin, up)\n * const axis = await snaptrude.core.geom.query.arc.getAxis(arc)\n * console.log(axis.x, axis.y, axis.z)\n * ```\n */\n public abstract getAxis(arc: ArcHandle): PluginApiReturn<Vec3Components>\n\n /**\n * Read the sweep angle of an arc (the angle subtended at its centre).\n *\n * @param arc The arc to query\n * @returns The sweep angle in radians as a `number`\n *\n * @examplePrompt What angle does this arc sweep through?\n * @examplePrompt How many degrees does this curved wall turn?\n *\n * # Example\n * ```ts\n * const start = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const end = await snaptrude.core.math.vec3.new(0, 0, 5)\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const arc = await snaptrude.core.geom.create.arc(start, end, origin, up)\n * const sweep = await snaptrude.core.geom.query.arc.getSweepAngle(arc)\n * console.log(\"degrees:\", (sweep * 180) / Math.PI)\n * ```\n */\n public abstract getSweepAngle(arc: ArcHandle): PluginApiReturn<number>\n\n /**\n * Check whether an arc is geometrically valid.\n *\n * @param arc The arc to query\n * @returns `true` if the arc is valid as a `boolean`\n *\n * # Example\n * ```ts\n * const start = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const end = await snaptrude.core.math.vec3.new(0, 0, 5)\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const arc = await snaptrude.core.geom.create.arc(start, end, origin, up)\n * const ok = await snaptrude.core.geom.query.arc.isValid(arc)\n * ```\n */\n public abstract isValid(arc: ArcHandle): PluginApiReturn<boolean>\n}\n\n/**\n * Arguments for {@linkcode PluginGeomQueryArcApi.getRadius}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `arc` | {@linkcode ArcHandle} | The arc to query |\n */\nexport const PluginGeomQueryArcGetRadiusArgs = z.object({ arc: ArcHandle })\nexport type PluginGeomQueryArcGetRadiusArgs = z.infer<typeof PluginGeomQueryArcGetRadiusArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryArcApi.getCentre}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `arc` | {@linkcode ArcHandle} | The arc to query |\n */\nexport const PluginGeomQueryArcGetCentreArgs = z.object({ arc: ArcHandle })\nexport type PluginGeomQueryArcGetCentreArgs = z.infer<typeof PluginGeomQueryArcGetCentreArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryArcApi.getAxis}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `arc` | {@linkcode ArcHandle} | The arc to query |\n */\nexport const PluginGeomQueryArcGetAxisArgs = z.object({ arc: ArcHandle })\nexport type PluginGeomQueryArcGetAxisArgs = z.infer<typeof PluginGeomQueryArcGetAxisArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryArcApi.getSweepAngle}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `arc` | {@linkcode ArcHandle} | The arc to query |\n */\nexport const PluginGeomQueryArcGetSweepAngleArgs = z.object({ arc: ArcHandle })\nexport type PluginGeomQueryArcGetSweepAngleArgs = z.infer<typeof PluginGeomQueryArcGetSweepAngleArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryArcApi.isValid}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `arc` | {@linkcode ArcHandle} | The arc to query |\n */\nexport const PluginGeomQueryArcIsValidArgs = z.object({ arc: ArcHandle })\nexport type PluginGeomQueryArcIsValidArgs = z.infer<typeof PluginGeomQueryArcIsValidArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport { CircleHandle, Vec3Handle, Vec3Components } from \"../../../../handles\"\n\n/**\n * Circle-specific geometry queries — read closed-circle properties as plain values\n * (all-handle model, §11). A circle is a closed curve with its own namespace\n * (mirroring {@linkcode PluginGeomQueryArcApi}); it is NOT part of the shared\n * {@linkcode CurveHandle} line/arc surface.\n *\n * Every method takes an opaque {@linkcode CircleHandle} (plus a point handle where\n * relevant) and returns plain values — numbers, {@linkcode Vec3Components},\n * predicates as `boolean`. No query mutates its inputs.\n *\n * Accessed via `snaptrude.core.geom.query.circle`.\n */\nexport abstract class PluginGeomQueryCircleApi {\n constructor() {}\n\n /**\n * Read the radius of a circle.\n * @param circle The circle to query\n * @returns The radius as a `number`\n *\n * @examplePrompt What is the radius of this circle?\n * @examplePrompt Measure the radius of the circular column grid\n *\n * # Example\n * ```ts\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const circle = await snaptrude.core.geom.create.circle(origin, up, 5)\n * const radius = await snaptrude.core.geom.query.circle.getRadius(circle)\n * ```\n */\n public abstract getRadius(circle: CircleHandle): PluginApiReturn<number>\n\n /**\n * Read the centre point of a circle.\n * @param circle The circle to query\n * @returns The centre as {@linkcode Vec3Components}\n *\n * @examplePrompt Where is the centre of this circle?\n * @examplePrompt Find the center point of the circular courtyard outline\n *\n * # Example\n * ```ts\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const circle = await snaptrude.core.geom.create.circle(origin, up, 5)\n * const centre = await snaptrude.core.geom.query.circle.getCentre(circle)\n * console.log(centre.x, centre.y, centre.z)\n * ```\n */\n public abstract getCentre(circle: CircleHandle): PluginApiReturn<Vec3Components>\n\n /**\n * Read the axis (plane normal) of a circle.\n * @param circle The circle to query\n * @returns The axis as {@linkcode Vec3Components}\n *\n * # Example\n * ```ts\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const circle = await snaptrude.core.geom.create.circle(origin, up, 5)\n * const axis = await snaptrude.core.geom.query.circle.getAxis(circle)\n * console.log(axis.x, axis.y, axis.z)\n * ```\n */\n public abstract getAxis(circle: CircleHandle): PluginApiReturn<Vec3Components>\n\n /**\n * Read the length (circumference, `2πr`) of a circle.\n * @param circle The circle to query\n * @returns The circumference as a `number`\n *\n * @examplePrompt What is the circumference of this circle?\n * @examplePrompt How long is the circular path around the courtyard?\n *\n * # Example\n * ```ts\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const circle = await snaptrude.core.geom.create.circle(origin, up, 5)\n * const circumference = await snaptrude.core.geom.query.circle.getLength(circle)\n * ```\n */\n public abstract getLength(circle: CircleHandle): PluginApiReturn<number>\n\n /**\n * Check whether a circle is geometrically valid (non-degenerate axis + positive radius).\n * @param circle The circle to query\n * @returns `true` if the circle is valid, otherwise `false`\n *\n * # Example\n * ```ts\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const circle = await snaptrude.core.geom.create.circle(origin, up, 5)\n * const ok = await snaptrude.core.geom.query.circle.isValid(circle)\n * ```\n */\n public abstract isValid(circle: CircleHandle): PluginApiReturn<boolean>\n\n /**\n * Get the point on a circle nearest to an arbitrary point.\n * @param circle The circle to query\n * @param point The reference point\n * @returns The nearest point as {@linkcode Vec3Components}\n *\n * @examplePrompt Find the point on the circle closest to this column\n *\n * # Example\n * ```ts\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const circle = await snaptrude.core.geom.create.circle(origin, up, 5)\n * const target = await snaptrude.core.math.vec3.new(8, 0, 2)\n * const nearest = await snaptrude.core.geom.query.circle.getNearestPoint(circle, target)\n * console.log(nearest.x, nearest.y, nearest.z)\n * ```\n */\n public abstract getNearestPoint(\n circle: CircleHandle,\n point: Vec3Handle\n ): PluginApiReturn<Vec3Components>\n\n /**\n * Test whether a point lies on a circle.\n * @param circle The circle to query\n * @param point The point to test\n * @returns `true` if the point is on the circle, otherwise `false`\n *\n * @examplePrompt Check whether this point sits on the circle\n *\n * # Example\n * ```ts\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const circle = await snaptrude.core.geom.create.circle(origin, up, 5)\n * const pt = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const onCircle = await snaptrude.core.geom.query.circle.hasPoint(circle, pt)\n * ```\n */\n public abstract hasPoint(circle: CircleHandle, point: Vec3Handle): PluginApiReturn<boolean>\n\n /**\n * Get the tangent direction of a circle at a point on it.\n * @param circle The circle to query\n * @param point A point on the circle\n * @returns The tangent as {@linkcode Vec3Components}\n *\n * # Example\n * ```ts\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const circle = await snaptrude.core.geom.create.circle(origin, up, 5)\n * const pt = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const tangent = await snaptrude.core.geom.query.circle.getTangent(circle, pt)\n * console.log(tangent.x, tangent.y, tangent.z)\n * ```\n */\n public abstract getTangent(circle: CircleHandle, point: Vec3Handle): PluginApiReturn<Vec3Components>\n\n /**\n * Get the (in-plane, radial) normal direction of a circle at a point on it.\n * @param circle The circle to query\n * @param point A point on the circle\n * @returns The radial normal as {@linkcode Vec3Components}\n *\n * # Example\n * ```ts\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const circle = await snaptrude.core.geom.create.circle(origin, up, 5)\n * const pt = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const normal = await snaptrude.core.geom.query.circle.getNormal(circle, pt)\n * console.log(normal.x, normal.y, normal.z)\n * ```\n */\n public abstract getNormal(circle: CircleHandle, point: Vec3Handle): PluginApiReturn<Vec3Components>\n\n /**\n * Get the point reached by travelling a signed arc-distance along the circle from\n * a reference point that lies on it.\n * @param circle The circle to query\n * @param referencePoint A point on the circle to travel from\n * @param distance Arc distance to travel\n * @param forward Travel direction (optional; default forward)\n * @returns The resulting point as {@linkcode Vec3Components}\n *\n * @examplePrompt Mark a point 2 metres along the circle from this point\n *\n * # Example\n * ```ts\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const circle = await snaptrude.core.geom.create.circle(origin, up, 5)\n * const ref = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const ahead = await snaptrude.core.geom.query.circle.getPointAtDistance(circle, ref, 2)\n * const behind = await snaptrude.core.geom.query.circle.getPointAtDistance(circle, ref, 2, false)\n * ```\n */\n public abstract getPointAtDistance(\n circle: CircleHandle,\n referencePoint: Vec3Handle,\n distance: number,\n forward?: boolean\n ): PluginApiReturn<Vec3Components>\n\n /**\n * Test whether two circles are geometrically equal.\n * @param circleA First circle\n * @param circleB Second circle\n * @returns `true` if the circles are equal, otherwise `false`\n *\n * # Example\n * ```ts\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const a = await snaptrude.core.geom.create.circle(origin, up, 5)\n * const b = await snaptrude.core.geom.create.circle(origin, up, 3)\n * const same = await snaptrude.core.geom.query.circle.isEqual(a, b)\n * ```\n */\n public abstract isEqual(circleA: CircleHandle, circleB: CircleHandle): PluginApiReturn<boolean>\n\n /**\n * Sample a circle into an ordered list of points.\n * @param circle The circle to query\n * @param resolution Number of segments to sample (optional)\n * @returns The sampled points as {@linkcode Vec3Components}`[]`\n *\n * @examplePrompt Divide this circle into 12 equal points\n * @examplePrompt Get evenly spaced points around the circle to place columns\n *\n * # Example\n * ```ts\n * const origin = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const up = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const circle = await snaptrude.core.geom.create.circle(origin, up, 5)\n * const points = await snaptrude.core.geom.query.circle.listPoints(circle, 12)\n * for (const p of points) console.log(p.x, p.y, p.z)\n * ```\n */\n public abstract listPoints(circle: CircleHandle, resolution?: number): PluginApiReturn<Vec3Components[]>\n}\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCircleApi.getRadius}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `circle` | {@linkcode CircleHandle} | The circle to query |\n */\nexport const PluginGeomQueryCircleGetRadiusArgs = z.object({ circle: CircleHandle })\nexport type PluginGeomQueryCircleGetRadiusArgs = z.infer<typeof PluginGeomQueryCircleGetRadiusArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCircleApi.getCentre}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `circle` | {@linkcode CircleHandle} | The circle to query |\n */\nexport const PluginGeomQueryCircleGetCentreArgs = z.object({ circle: CircleHandle })\nexport type PluginGeomQueryCircleGetCentreArgs = z.infer<typeof PluginGeomQueryCircleGetCentreArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCircleApi.getAxis}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `circle` | {@linkcode CircleHandle} | The circle to query |\n */\nexport const PluginGeomQueryCircleGetAxisArgs = z.object({ circle: CircleHandle })\nexport type PluginGeomQueryCircleGetAxisArgs = z.infer<typeof PluginGeomQueryCircleGetAxisArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCircleApi.getLength}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `circle` | {@linkcode CircleHandle} | The circle to query |\n */\nexport const PluginGeomQueryCircleGetLengthArgs = z.object({ circle: CircleHandle })\nexport type PluginGeomQueryCircleGetLengthArgs = z.infer<typeof PluginGeomQueryCircleGetLengthArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCircleApi.isValid}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `circle` | {@linkcode CircleHandle} | The circle to query |\n */\nexport const PluginGeomQueryCircleIsValidArgs = z.object({ circle: CircleHandle })\nexport type PluginGeomQueryCircleIsValidArgs = z.infer<typeof PluginGeomQueryCircleIsValidArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCircleApi.getNearestPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `circle` | {@linkcode CircleHandle} | The circle to query |\n * | `point` | {@linkcode Vec3Handle} | The reference point |\n */\nexport const PluginGeomQueryCircleGetNearestPointArgs = z.object({\n circle: CircleHandle,\n point: Vec3Handle,\n})\nexport type PluginGeomQueryCircleGetNearestPointArgs = z.infer<\n typeof PluginGeomQueryCircleGetNearestPointArgs\n>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCircleApi.hasPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `circle` | {@linkcode CircleHandle} | The circle to query |\n * | `point` | {@linkcode Vec3Handle} | The point to test |\n */\nexport const PluginGeomQueryCircleHasPointArgs = z.object({\n circle: CircleHandle,\n point: Vec3Handle,\n})\nexport type PluginGeomQueryCircleHasPointArgs = z.infer<typeof PluginGeomQueryCircleHasPointArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCircleApi.getTangent}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `circle` | {@linkcode CircleHandle} | The circle to query |\n * | `point` | {@linkcode Vec3Handle} | A point on the circle |\n */\nexport const PluginGeomQueryCircleGetTangentArgs = z.object({\n circle: CircleHandle,\n point: Vec3Handle,\n})\nexport type PluginGeomQueryCircleGetTangentArgs = z.infer<typeof PluginGeomQueryCircleGetTangentArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCircleApi.getNormal}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `circle` | {@linkcode CircleHandle} | The circle to query |\n * | `point` | {@linkcode Vec3Handle} | A point on the circle |\n */\nexport const PluginGeomQueryCircleGetNormalArgs = z.object({\n circle: CircleHandle,\n point: Vec3Handle,\n})\nexport type PluginGeomQueryCircleGetNormalArgs = z.infer<typeof PluginGeomQueryCircleGetNormalArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCircleApi.getPointAtDistance}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `circle` | {@linkcode CircleHandle} | The circle to query |\n * | `referencePoint` | {@linkcode Vec3Handle} | A point on the circle to travel from |\n * | `distance` | `number` | Arc distance to travel |\n * | `forward` | `boolean` | Travel direction (optional; default forward) |\n */\nexport const PluginGeomQueryCircleGetPointAtDistanceArgs = z.object({\n circle: CircleHandle,\n referencePoint: Vec3Handle,\n distance: z.number(),\n forward: z.boolean().optional(),\n})\nexport type PluginGeomQueryCircleGetPointAtDistanceArgs = z.infer<\n typeof PluginGeomQueryCircleGetPointAtDistanceArgs\n>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCircleApi.isEqual}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `circleA` | {@linkcode CircleHandle} | First circle |\n * | `circleB` | {@linkcode CircleHandle} | Second circle |\n */\nexport const PluginGeomQueryCircleIsEqualArgs = z.object({\n circleA: CircleHandle,\n circleB: CircleHandle,\n})\nexport type PluginGeomQueryCircleIsEqualArgs = z.infer<typeof PluginGeomQueryCircleIsEqualArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryCircleApi.listPoints}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `circle` | {@linkcode CircleHandle} | The circle to query |\n * | `resolution` | `number` | Number of segments to sample (optional) |\n */\nexport const PluginGeomQueryCircleListPointsArgs = z.object({\n circle: CircleHandle,\n resolution: z.number().optional(),\n})\nexport type PluginGeomQueryCircleListPointsArgs = z.infer<typeof PluginGeomQueryCircleListPointsArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport {\n ProfileHandle,\n Vec3Handle,\n CurveHandle,\n Vec3Components,\n BBoxComponents,\n} from \"../../../../handles\"\n\n/**\n * Profile queries — read-only geometric questions about a profile (an ordered\n * loop or chain of curves) and the relationships between two profiles\n * (all-handle model, §11).\n *\n * Every method takes an opaque {@linkcode ProfileHandle} (plus point handles\n * {@linkcode Vec3Handle} where relevant) and returns plain values — points as\n * {@linkcode Vec3Components}, areas/perimeters/distances as `number`, predicates\n * as `boolean`, the bounding box as {@linkcode BBoxComponents}. Methods that\n * enumerate the profile's child curves return fresh {@linkcode CurveHandle}`[]`.\n * No query mutates its inputs.\n *\n * Accessed via `snaptrude.core.geom.query.profile`.\n */\nexport abstract class PluginGeomQueryProfileApi {\n constructor() {}\n\n /**\n * List the tessellated points along a profile.\n * @param profile The profile to query\n * @returns The profile points as {@linkcode Vec3Components}`[]`\n *\n * @examplePrompt Give me the corner coordinates of this shape\n * @examplePrompt List the vertex points along this outline\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const points = await snaptrude.core.geom.query.profile.listPoints(rect)\n * for (const p of points) console.log(p.x, p.y, p.z)\n * ```\n */\n public abstract listPoints(profile: ProfileHandle): PluginApiReturn<Vec3Components[]>\n\n /**\n * List the curves that make up a profile. Host API call — mints fresh handles.\n * @param profile The profile to query\n * @returns The profile's curves as {@linkcode CurveHandle}`[]`\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const curves = await snaptrude.core.geom.query.profile.listCurves(rect)\n * for (const c of curves) console.log(await snaptrude.core.geom.query.curve.getLength(c))\n * ```\n */\n public abstract listCurves(profile: ProfileHandle): PluginApiReturn<CurveHandle[]>\n\n /**\n * Get the (approximate) enclosed area of a profile.\n * @param profile The profile to query\n * @returns The area as a `number`\n *\n * @examplePrompt What is the area enclosed by this outline?\n * @examplePrompt Measure the area of this shape\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const area = await snaptrude.core.geom.query.profile.getArea(rect) // 12\n * ```\n */\n public abstract getArea(profile: ProfileHandle): PluginApiReturn<number>\n\n /**\n * Get the perimeter (total curve length) of a profile.\n * @param profile The profile to query\n * @returns The perimeter as a `number`\n *\n * @examplePrompt How long is the boundary of this shape in total?\n * @examplePrompt Measure the perimeter of this outline\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const perimeter = await snaptrude.core.geom.query.profile.getPerimeter(rect) // 14\n * ```\n */\n public abstract getPerimeter(profile: ProfileHandle): PluginApiReturn<number>\n\n /**\n * Get the axis-aligned bounding box of a profile.\n * @param profile The profile to query\n * @returns The bounding box as {@linkcode BBoxComponents}\n *\n * @examplePrompt How wide and long is this outline overall?\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const { min, max } = await snaptrude.core.geom.query.profile.getBoundingBox(rect)\n * console.log(max.x - min.x, max.z - min.z) // 4 3\n * ```\n */\n public abstract getBoundingBox(profile: ProfileHandle): PluginApiReturn<BBoxComponents>\n\n /**\n * Get the unit normal vector of a profile's plane.\n * @param profile The profile to query\n * @returns The normal as {@linkcode Vec3Components}, or `null` if the profile has no well-defined normal\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const normal = await snaptrude.core.geom.query.profile.getNormal(rect)\n * if (normal) console.log(normal.x, normal.y, normal.z)\n * ```\n */\n public abstract getNormal(profile: ProfileHandle): PluginApiReturn<Vec3Components | null>\n\n /**\n * Get the point on a profile nearest to an arbitrary point.\n * @param profile The profile to query\n * @param point The reference point\n * @returns The nearest point on the profile as {@linkcode Vec3Components}\n *\n * @examplePrompt Find the closest point on this outline to a given point\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const point = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const nearest = await snaptrude.core.geom.query.profile.getNearestPoint(rect, point)\n * console.log(nearest.x, nearest.y, nearest.z) // 2 0 0\n * ```\n */\n public abstract getNearestPoint(\n profile: ProfileHandle,\n point: Vec3Handle,\n ): PluginApiReturn<Vec3Components>\n\n /**\n * Test whether a point lies inside a profile.\n * @param profile The profile to query\n * @param point The point to test\n * @returns `true` if the point is inside the profile, otherwise `false`\n *\n * @examplePrompt Does this point fall inside the outline?\n * @examplePrompt Check if the column location lies within this room boundary\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const point = await snaptrude.core.math.vec3.new(1, 0, 1)\n * const inside = await snaptrude.core.geom.query.profile.hasPoint(rect, point) // true\n * ```\n */\n public abstract hasPoint(\n profile: ProfileHandle,\n point: Vec3Handle,\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether a point lies on a profile's boundary.\n * @param profile The profile to query\n * @param point The point to test\n * @returns `true` if the point is on the boundary, otherwise `false`\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const point = await snaptrude.core.math.vec3.new(2, 0, 0)\n * const onEdge = await snaptrude.core.geom.query.profile.isOnBoundary(rect, point) // true\n * ```\n */\n public abstract isOnBoundary(\n profile: ProfileHandle,\n point: Vec3Handle,\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether a profile forms a closed loop.\n * @param profile The profile to query\n * @returns `true` if the profile is closed, otherwise `false`\n *\n * @examplePrompt Is my sketch outline closed or still open?\n * @examplePrompt Check whether this boundary forms a complete loop\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const closed = await snaptrude.core.geom.query.profile.isClosed(rect) // true\n * ```\n */\n public abstract isClosed(profile: ProfileHandle): PluginApiReturn<boolean>\n\n /**\n * Test whether a profile is planar.\n * @param profile The profile to query\n * @returns `true` if the profile is planar, otherwise `false`\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const planar = await snaptrude.core.geom.query.profile.isPlanar(rect) // true\n * ```\n */\n public abstract isPlanar(profile: ProfileHandle): PluginApiReturn<boolean>\n\n /**\n * Test whether a profile is wound clockwise on the XZ plane.\n * @param profile The profile to query\n * @returns `true` if the profile is clockwise, otherwise `false`\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const clockwise = await snaptrude.core.geom.query.profile.isClockwise(rect)\n * ```\n */\n public abstract isClockwise(profile: ProfileHandle): PluginApiReturn<boolean>\n\n /**\n * Test whether a profile intersects itself.\n * @param profile The profile to query\n * @returns `true` if the profile is self-intersecting, otherwise `false`\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(2, 0, 2)\n * const c = await snaptrude.core.math.vec3.new(2, 0, 0)\n * const d = await snaptrude.core.math.vec3.new(0, 0, 2)\n * const bowtie = await snaptrude.core.geom.create.profileFromLinePoints([a, b, c, d])\n * const crossed = await snaptrude.core.geom.query.profile.isSelfIntersecting(bowtie) // true\n * ```\n */\n public abstract isSelfIntersecting(profile: ProfileHandle): PluginApiReturn<boolean>\n\n /**\n * Test whether a profile contains no curves.\n * @param profile The profile to query\n * @returns `true` if the profile is empty, otherwise `false`\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const empty = await snaptrude.core.geom.query.profile.isEmpty(rect) // false\n * ```\n */\n public abstract isEmpty(profile: ProfileHandle): PluginApiReturn<boolean>\n\n /**\n * Test whether two profiles are geometrically equal.\n * @param profileA First profile\n * @param profileB Second profile\n * @returns `true` if the profiles are equal, otherwise `false`\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.geom.create.profileRect(4, 3)\n * const b = await snaptrude.core.geom.create.profileRect(4, 3)\n * const same = await snaptrude.core.geom.query.profile.isEqual(a, b) // true\n * ```\n */\n public abstract isEqual(\n profileA: ProfileHandle,\n profileB: ProfileHandle,\n ): PluginApiReturn<boolean>\n}\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.listPoints}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n */\nexport const PluginGeomQueryProfileListPointsArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomQueryProfileListPointsArgs = z.infer<typeof PluginGeomQueryProfileListPointsArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.listCurves}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n */\nexport const PluginGeomQueryProfileListCurvesArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomQueryProfileListCurvesArgs = z.infer<typeof PluginGeomQueryProfileListCurvesArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.getArea}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n */\nexport const PluginGeomQueryProfileGetAreaArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomQueryProfileGetAreaArgs = z.infer<typeof PluginGeomQueryProfileGetAreaArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.getPerimeter}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n */\nexport const PluginGeomQueryProfileGetPerimeterArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomQueryProfileGetPerimeterArgs = z.infer<typeof PluginGeomQueryProfileGetPerimeterArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.getBoundingBox}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n */\nexport const PluginGeomQueryProfileGetBoundingBoxArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomQueryProfileGetBoundingBoxArgs = z.infer<typeof PluginGeomQueryProfileGetBoundingBoxArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.getNormal}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n */\nexport const PluginGeomQueryProfileGetNormalArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomQueryProfileGetNormalArgs = z.infer<typeof PluginGeomQueryProfileGetNormalArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.getNearestPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n * | `point` | {@linkcode Vec3Handle} | The reference point |\n */\nexport const PluginGeomQueryProfileGetNearestPointArgs = z.object({\n profile: ProfileHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryProfileGetNearestPointArgs = z.infer<typeof PluginGeomQueryProfileGetNearestPointArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.hasPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n * | `point` | {@linkcode Vec3Handle} | The point to test |\n */\nexport const PluginGeomQueryProfileHasPointArgs = z.object({\n profile: ProfileHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryProfileHasPointArgs = z.infer<typeof PluginGeomQueryProfileHasPointArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.isOnBoundary}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n * | `point` | {@linkcode Vec3Handle} | The point to test |\n */\nexport const PluginGeomQueryProfileIsOnBoundaryArgs = z.object({\n profile: ProfileHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryProfileIsOnBoundaryArgs = z.infer<typeof PluginGeomQueryProfileIsOnBoundaryArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.isClosed}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n */\nexport const PluginGeomQueryProfileIsClosedArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomQueryProfileIsClosedArgs = z.infer<typeof PluginGeomQueryProfileIsClosedArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.isPlanar}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n */\nexport const PluginGeomQueryProfileIsPlanarArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomQueryProfileIsPlanarArgs = z.infer<typeof PluginGeomQueryProfileIsPlanarArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.isClockwise}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n */\nexport const PluginGeomQueryProfileIsClockwiseArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomQueryProfileIsClockwiseArgs = z.infer<typeof PluginGeomQueryProfileIsClockwiseArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.isSelfIntersecting}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n */\nexport const PluginGeomQueryProfileIsSelfIntersectingArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomQueryProfileIsSelfIntersectingArgs = z.infer<typeof PluginGeomQueryProfileIsSelfIntersectingArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.isEmpty}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to query |\n */\nexport const PluginGeomQueryProfileIsEmptyArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomQueryProfileIsEmptyArgs = z.infer<typeof PluginGeomQueryProfileIsEmptyArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryProfileApi.isEqual}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profileA` | {@linkcode ProfileHandle} | First profile |\n * | `profileB` | {@linkcode ProfileHandle} | Second profile |\n */\nexport const PluginGeomQueryProfileIsEqualArgs = z.object({\n profileA: ProfileHandle,\n profileB: ProfileHandle,\n})\n\nexport type PluginGeomQueryProfileIsEqualArgs = z.infer<typeof PluginGeomQueryProfileIsEqualArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport {\n ContourHandle,\n ProfileHandle,\n Vec3Handle,\n Vec3Components,\n BBoxComponents,\n} from \"../../../../handles\"\n\n/**\n * Contour queries — read-only geometric questions about a contour (an outer\n * {@linkcode ProfileHandle} plus zero or more inner profiles that act as holes)\n * and the relationships between two contours (all-handle model, §11).\n *\n * Every method takes an opaque {@linkcode ContourHandle} (plus point handles\n * {@linkcode Vec3Handle} where relevant) and returns plain values — points as\n * {@linkcode Vec3Components}, areas/perimeters/counts as `number`, predicates as\n * `boolean`, the bounding box as {@linkcode BBoxComponents}. Methods that\n * enumerate the contour's child profiles return fresh {@linkcode ProfileHandle}s.\n * No query mutates its inputs.\n *\n * Accessed via `snaptrude.core.geom.query.contour`.\n */\nexport abstract class PluginGeomQueryContourApi {\n constructor() {}\n\n /**\n * Get the outer (boundary) profile of a contour. Host API call — mints a fresh handle.\n * @param contour The contour to query\n * @returns The outer profile as a {@linkcode ProfileHandle}, or `null` if the contour has no outer profile\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const outer = await snaptrude.core.geom.query.contour.getOuterProfile(contour)\n * if (outer) console.log(await snaptrude.core.geom.query.profile.getPerimeter(outer))\n * ```\n */\n public abstract getOuterProfile(\n contour: ContourHandle\n ): PluginApiReturn<ProfileHandle | null>\n\n /**\n * List the inner profiles (holes) of a contour. Host API call — mints fresh handles.\n * @param contour The contour to query\n * @returns The contour's holes as {@linkcode ProfileHandle}`[]`\n *\n * # Example\n * ```ts\n * const outer = await snaptrude.core.geom.create.profileRect(6, 4)\n * const hole = await snaptrude.core.geom.create.profileRect(2, 1)\n * const contour = await snaptrude.core.geom.create.contourFromProfiles(outer, [hole])\n * const holes = await snaptrude.core.geom.query.contour.listHoles(contour)\n * for (const h of holes) console.log(await snaptrude.core.geom.query.profile.getArea(h))\n * ```\n */\n public abstract listHoles(\n contour: ContourHandle\n ): PluginApiReturn<ProfileHandle[]>\n\n /**\n * Get the number of inner profiles (holes) in a contour.\n * @param contour The contour to query\n * @returns The hole count as a `number`\n *\n * @examplePrompt How many holes does this shape have?\n * @examplePrompt Count the openings in this slab outline\n *\n * # Example\n * ```ts\n * const outer = await snaptrude.core.geom.create.profileRect(6, 4)\n * const hole = await snaptrude.core.geom.create.profileRect(2, 1)\n * const contour = await snaptrude.core.geom.create.contourFromProfiles(outer, [hole])\n * const count = await snaptrude.core.geom.query.contour.getHoleCount(contour) // 1\n * ```\n */\n public abstract getHoleCount(\n contour: ContourHandle\n ): PluginApiReturn<number>\n\n /**\n * Get the (approximate) net enclosed area of a contour — the outer profile area\n * minus the area of every hole.\n * @param contour The contour to query\n * @returns The area as a `number`\n *\n * @examplePrompt What is the area of this shape?\n * @examplePrompt Calculate the usable area of this outline after subtracting its holes\n *\n * # Example\n * ```ts\n * const outer = await snaptrude.core.geom.create.profileRect(6, 4)\n * const hole = await snaptrude.core.geom.create.profileRect(2, 1)\n * const contour = await snaptrude.core.geom.create.contourFromProfiles(outer, [hole])\n * const area = await snaptrude.core.geom.query.contour.getArea(contour) // 24 - 2 = 22\n * ```\n */\n public abstract getArea(\n contour: ContourHandle\n ): PluginApiReturn<number>\n\n /**\n * Get the perimeter (total length of every curve) of a contour, including holes.\n * @param contour The contour to query\n * @returns The perimeter as a `number`\n *\n * @examplePrompt What is the perimeter of this shape?\n * @examplePrompt How long is the boundary of this outline, including its holes?\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const perimeter = await snaptrude.core.geom.query.contour.getPerimeter(contour) // 14\n * ```\n */\n public abstract getPerimeter(\n contour: ContourHandle\n ): PluginApiReturn<number>\n\n /**\n * Get the axis-aligned bounding box of a contour.\n * @param contour The contour to query\n * @returns The bounding box as {@linkcode BBoxComponents}\n *\n * @examplePrompt What are the overall extents of this shape?\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const { min, max } = await snaptrude.core.geom.query.contour.getBoundingBox(contour)\n * console.log(max.x - min.x, max.z - min.z) // 4 3\n * ```\n */\n public abstract getBoundingBox(\n contour: ContourHandle\n ): PluginApiReturn<BBoxComponents>\n\n /**\n * Get the unit normal vector of a contour's plane.\n * @param contour The contour to query\n * @returns The normal as {@linkcode Vec3Components}, or `null` if the contour has no well-defined normal\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const normal = await snaptrude.core.geom.query.contour.getNormal(contour)\n * if (normal) console.log(normal.x, normal.y, normal.z)\n * ```\n */\n public abstract getNormal(\n contour: ContourHandle\n ): PluginApiReturn<Vec3Components | null>\n\n /**\n * Get the point on a contour nearest to an arbitrary point.\n * @param contour The contour to query\n * @param point The reference point\n * @returns The nearest point on the contour as {@linkcode Vec3Components}\n *\n * @examplePrompt Find the point on this boundary closest to a given location\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const point = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const nearest = await snaptrude.core.geom.query.contour.getNearestPoint(contour, point)\n * console.log(nearest.x, nearest.y, nearest.z) // 2 0 0\n * ```\n */\n public abstract getNearestPoint(\n contour: ContourHandle,\n point: Vec3Handle\n ): PluginApiReturn<Vec3Components>\n\n /**\n * Test whether a point lies inside a contour (inside the outer profile and\n * outside every hole).\n * @param contour The contour to query\n * @param point The point to test\n * @returns `true` if the point is inside the contour, otherwise `false`\n *\n * @examplePrompt Is this point inside the shape?\n * @examplePrompt Check whether a location falls within this boundary but not in a hole\n *\n * # Example\n * ```ts\n * const outer = await snaptrude.core.geom.create.profileRect(6, 4)\n * const hole = await snaptrude.core.geom.create.profileRect(2, 1)\n * const contour = await snaptrude.core.geom.create.contourFromProfiles(outer, [hole])\n * const point = await snaptrude.core.math.vec3.new(2.5, 0, 1.5)\n * const inside = await snaptrude.core.geom.query.contour.hasPoint(contour, point) // true — outside the hole\n * ```\n */\n public abstract hasPoint(\n contour: ContourHandle,\n point: Vec3Handle\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether a point lies on a contour's boundary (any of its curves).\n * @param contour The contour to query\n * @param point The point to test\n * @returns `true` if the point is on the boundary, otherwise `false`\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const point = await snaptrude.core.math.vec3.new(2, 0, 0)\n * const onEdge = await snaptrude.core.geom.query.contour.isOnBoundary(contour, point) // true\n * ```\n */\n public abstract isOnBoundary(\n contour: ContourHandle,\n point: Vec3Handle\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether a contour's outer profile is wound clockwise on the XZ plane.\n * @param contour The contour to query\n * @returns `true` if the contour is clockwise, otherwise `false`\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const clockwise = await snaptrude.core.geom.query.contour.isClockwise(contour)\n * ```\n */\n public abstract isClockwise(\n contour: ContourHandle\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether a contour is planar.\n * @param contour The contour to query\n * @returns `true` if the contour is planar, otherwise `false`\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const planar = await snaptrude.core.geom.query.contour.isPlanar(contour) // true\n * ```\n */\n public abstract isPlanar(\n contour: ContourHandle\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether a contour is empty (its outer profile contains no curves).\n * @param contour The contour to query\n * @returns `true` if the contour is empty, otherwise `false`\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const empty = await snaptrude.core.geom.query.contour.isEmpty(contour) // false\n * ```\n */\n public abstract isEmpty(\n contour: ContourHandle\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether a contour intersects itself.\n * @param contour The contour to query\n * @returns `true` if the contour is self-intersecting, otherwise `false`\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const crossed = await snaptrude.core.geom.query.contour.isSelfIntersecting(contour) // false\n * ```\n */\n public abstract isSelfIntersecting(\n contour: ContourHandle\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether a contour's orientation is valid (outer profile and holes are\n * wound consistently).\n * @param contour The contour to query\n * @returns `true` if the orientation is valid, otherwise `false`\n *\n * # Example\n * ```ts\n * const outer = await snaptrude.core.geom.create.profileRect(6, 4)\n * const hole = await snaptrude.core.geom.create.profileRect(2, 1)\n * const contour = await snaptrude.core.geom.create.contourFromProfiles(outer, [hole])\n * const valid = await snaptrude.core.geom.query.contour.isOrientationValid(contour)\n * ```\n */\n public abstract isOrientationValid(\n contour: ContourHandle\n ): PluginApiReturn<boolean>\n\n /**\n * Test whether two contours are geometrically equal.\n * @param contourA First contour\n * @param contourB Second contour\n * @returns `true` if the contours are equal, otherwise `false`\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const a = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const b = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const same = await snaptrude.core.geom.query.contour.isEqual(a, b) // true\n * ```\n */\n public abstract isEqual(\n contourA: ContourHandle,\n contourB: ContourHandle\n ): PluginApiReturn<boolean>\n}\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.getOuterProfile}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n */\nexport const PluginGeomQueryContourGetOuterProfileArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomQueryContourGetOuterProfileArgs = z.infer<typeof PluginGeomQueryContourGetOuterProfileArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.listHoles}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n */\nexport const PluginGeomQueryContourListHolesArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomQueryContourListHolesArgs = z.infer<typeof PluginGeomQueryContourListHolesArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.getHoleCount}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n */\nexport const PluginGeomQueryContourGetHoleCountArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomQueryContourGetHoleCountArgs = z.infer<typeof PluginGeomQueryContourGetHoleCountArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.getArea}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n */\nexport const PluginGeomQueryContourGetAreaArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomQueryContourGetAreaArgs = z.infer<typeof PluginGeomQueryContourGetAreaArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.getPerimeter}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n */\nexport const PluginGeomQueryContourGetPerimeterArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomQueryContourGetPerimeterArgs = z.infer<typeof PluginGeomQueryContourGetPerimeterArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.getBoundingBox}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n */\nexport const PluginGeomQueryContourGetBoundingBoxArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomQueryContourGetBoundingBoxArgs = z.infer<typeof PluginGeomQueryContourGetBoundingBoxArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.getNormal}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n */\nexport const PluginGeomQueryContourGetNormalArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomQueryContourGetNormalArgs = z.infer<typeof PluginGeomQueryContourGetNormalArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.getNearestPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n * | `point` | {@linkcode Vec3Handle} | The reference point |\n */\nexport const PluginGeomQueryContourGetNearestPointArgs = z.object({\n contour: ContourHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryContourGetNearestPointArgs = z.infer<typeof PluginGeomQueryContourGetNearestPointArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.hasPoint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n * | `point` | {@linkcode Vec3Handle} | The point to test |\n */\nexport const PluginGeomQueryContourHasPointArgs = z.object({\n contour: ContourHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryContourHasPointArgs = z.infer<typeof PluginGeomQueryContourHasPointArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.isOnBoundary}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n * | `point` | {@linkcode Vec3Handle} | The point to test |\n */\nexport const PluginGeomQueryContourIsOnBoundaryArgs = z.object({\n contour: ContourHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomQueryContourIsOnBoundaryArgs = z.infer<typeof PluginGeomQueryContourIsOnBoundaryArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.isClockwise}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n */\nexport const PluginGeomQueryContourIsClockwiseArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomQueryContourIsClockwiseArgs = z.infer<typeof PluginGeomQueryContourIsClockwiseArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.isPlanar}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n */\nexport const PluginGeomQueryContourIsPlanarArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomQueryContourIsPlanarArgs = z.infer<typeof PluginGeomQueryContourIsPlanarArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.isEmpty}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n */\nexport const PluginGeomQueryContourIsEmptyArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomQueryContourIsEmptyArgs = z.infer<typeof PluginGeomQueryContourIsEmptyArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.isSelfIntersecting}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n */\nexport const PluginGeomQueryContourIsSelfIntersectingArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomQueryContourIsSelfIntersectingArgs = z.infer<typeof PluginGeomQueryContourIsSelfIntersectingArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.isOrientationValid}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to query |\n */\nexport const PluginGeomQueryContourIsOrientationValidArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomQueryContourIsOrientationValidArgs = z.infer<typeof PluginGeomQueryContourIsOrientationValidArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryContourApi.isEqual}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contourA` | {@linkcode ContourHandle} | First contour |\n * | `contourB` | {@linkcode ContourHandle} | Second contour |\n */\nexport const PluginGeomQueryContourIsEqualArgs = z.object({\n contourA: ContourHandle,\n contourB: ContourHandle,\n})\n\nexport type PluginGeomQueryContourIsEqualArgs = z.infer<typeof PluginGeomQueryContourIsEqualArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport {\n BrepHandle,\n FaceHandle,\n EdgeHandle,\n VertexHandle,\n HalfEdgeHandle,\n Vec3Components,\n BBoxComponents,\n} from \"../../../../handles\"\n\n/**\n * BREP queries — read the topology and geometry of a boundary-representation mesh\n * as plain values / child handles (all-handle model, §11). A {@linkcode BrepHandle}\n * is a session-ephemeral resource handle obtained from `design.query.geometry.getBrep`;\n * it goes stale on undo/redo/re-topologize.\n *\n * Enumerations mint fresh child topology handles ({@linkcode FaceHandle},\n * {@linkcode EdgeHandle}, {@linkcode VertexHandle}, {@linkcode HalfEdgeHandle}); the\n * registry dedupes by identity, so re-enumeration returns the same handles. Position\n * reads return {@linkcode Vec3Components}. No query mutates its inputs.\n *\n * Accessed via `snaptrude.core.geom.query.brep`.\n */\nexport abstract class PluginGeomQueryBrepApi {\n constructor() {}\n\n /**\n * List the faces of a brep.\n * @param brep The brep to query\n * @returns The faces as {@linkcode FaceHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const faces = await snaptrude.core.geom.query.brep.listFaces(brep)\n * }\n * ```\n */\n public abstract listFaces(brep: BrepHandle): PluginApiReturn<FaceHandle[]>\n\n /**\n * List the edges of a brep.\n * @param brep The brep to query\n * @returns The edges as {@linkcode EdgeHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const edges = await snaptrude.core.geom.query.brep.listEdges(brep)\n * }\n * ```\n */\n public abstract listEdges(brep: BrepHandle): PluginApiReturn<EdgeHandle[]>\n\n /**\n * List the vertices of a brep.\n * @param brep The brep to query\n * @returns The vertices as {@linkcode VertexHandle}`[]`\n *\n * # Example\n * ```ts\n * const [mass] = await snaptrude.design.query.listMasses()\n * const brep = await snaptrude.design.query.geometry.getBrep(mass)\n * if (brep) {\n * const vertices = await snaptrude.core.geom.query.brep.listVertices(brep)\n * }\n * ```\n */\n public abstract listVertices(brep: BrepHandle): PluginApiReturn<VertexHandle[]>\n\n /**\n * List the half-edges of a brep.\n * @param brep The brep to query\n * @returns The half-edges as {@linkcode HalfEdgeHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const halfEdges = await snaptrude.core.geom.query.brep.listHalfEdges(brep)\n * }\n * ```\n */\n public abstract listHalfEdges(brep: BrepHandle): PluginApiReturn<HalfEdgeHandle[]>\n\n /**\n * Get the edge connecting two vertices (by their brep vertex indices).\n * @param brep The brep to query\n * @param vertexIndexA First vertex index\n * @param vertexIndexB Second vertex index\n * @returns The edge as an {@linkcode EdgeHandle}, or `null` if no such edge exists\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [va, vb] = await snaptrude.core.geom.query.brep.listVertices(brep)\n * const ia = await snaptrude.core.geom.query.vertex.getIndex(va)\n * const ib = await snaptrude.core.geom.query.vertex.getIndex(vb)\n * const edge = await snaptrude.core.geom.query.brep.getEdge(brep, ia, ib)\n * if (edge) console.log(\"those two vertices are connected\")\n * }\n * ```\n */\n public abstract getEdge(\n brep: BrepHandle,\n vertexIndexA: number,\n vertexIndexB: number\n ): PluginApiReturn<EdgeHandle | null>\n\n /**\n * Test whether an edge connects two vertices (by their brep vertex indices).\n * @param brep The brep to query\n * @param vertexIndexA First vertex index\n * @param vertexIndexB Second vertex index\n * @returns `true` if such an edge exists, otherwise `false`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * // brep vertex indices (get one from core.geom.query.vertex.getIndex)\n * const connected = await snaptrude.core.geom.query.brep.hasEdge(brep, 0, 1)\n * }\n * ```\n */\n public abstract hasEdge(\n brep: BrepHandle,\n vertexIndexA: number,\n vertexIndexB: number\n ): PluginApiReturn<boolean>\n\n /**\n * List every edge connecting two vertices (by their brep vertex indices).\n * @param brep The brep to query\n * @param vertexIndexA First vertex index\n * @param vertexIndexB Second vertex index\n * @returns The edges as {@linkcode EdgeHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * // brep vertex indices (get one from core.geom.query.vertex.getIndex)\n * const edges = await snaptrude.core.geom.query.brep.listEdgesBetween(brep, 0, 1)\n * console.log(\"edges between vertices 0 and 1:\", edges.length)\n * }\n * ```\n */\n public abstract listEdgesBetween(\n brep: BrepHandle,\n vertexIndexA: number,\n vertexIndexB: number\n ): PluginApiReturn<EdgeHandle[]>\n\n /**\n * Get the position of a vertex within a brep.\n * @param brep The brep to query\n * @param vertex The vertex whose position to read\n * @returns The position as {@linkcode Vec3Components}\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [vertex] = await snaptrude.core.geom.query.brep.listVertices(brep)\n * const { x, y, z } = await snaptrude.core.geom.query.brep.getVertexPosition(brep, vertex)\n * }\n * ```\n */\n public abstract getVertexPosition(\n brep: BrepHandle,\n vertex: VertexHandle\n ): PluginApiReturn<Vec3Components>\n\n /**\n * List the positions of all vertices in a brep (ordered as {@linkcode PluginGeomQueryBrepApi.listVertices}).\n * @param brep The brep to query\n * @returns The positions as {@linkcode Vec3Components}`[]`\n *\n * @examplePrompt Get the coordinates of every corner of this shape\n * @examplePrompt Give me all the corner points of the selected mass as XYZ coordinates\n *\n * # Example\n * ```ts\n * const [mass] = await snaptrude.design.query.listMasses()\n * const brep = await snaptrude.design.query.geometry.getBrep(mass)\n * if (brep) {\n * const positions = await snaptrude.core.geom.query.brep.listVertexPositions(brep)\n * for (const p of positions) console.log(p.x, p.y, p.z)\n * }\n * ```\n */\n public abstract listVertexPositions(brep: BrepHandle): PluginApiReturn<Vec3Components[]>\n\n /**\n * Get the centroid (mean of all vertex positions) of a brep.\n * @param brep The brep to query\n * @returns The centroid as {@linkcode Vec3Components}\n *\n * @examplePrompt Find the centre point of this shape\n * @examplePrompt What is the centroid of the selected object?\n *\n * # Example\n * ```ts\n * const [mass] = await snaptrude.design.query.listMasses()\n * const brep = await snaptrude.design.query.geometry.getBrep(mass)\n * if (brep) {\n * const centroid = await snaptrude.core.geom.query.brep.getCentroid(brep)\n * console.log(centroid.x, centroid.y, centroid.z)\n * }\n * ```\n */\n public abstract getCentroid(brep: BrepHandle): PluginApiReturn<Vec3Components>\n\n /**\n * Get the number of faces in a brep.\n * @param brep The brep to query\n * @returns The face count as a `number`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const faceCount = await snaptrude.core.geom.query.brep.getFaceCount(brep)\n * }\n * ```\n */\n public abstract getFaceCount(brep: BrepHandle): PluginApiReturn<number>\n\n /**\n * Get the number of edges in a brep.\n * @param brep The brep to query\n * @returns The edge count as a `number`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const edgeCount = await snaptrude.core.geom.query.brep.getEdgeCount(brep)\n * }\n * ```\n */\n public abstract getEdgeCount(brep: BrepHandle): PluginApiReturn<number>\n\n /**\n * Get the number of vertices in a brep.\n * @param brep The brep to query\n * @returns The vertex count as a `number`\n *\n * # Example\n * ```ts\n * const [mass] = await snaptrude.design.query.listMasses()\n * const brep = await snaptrude.design.query.geometry.getBrep(mass)\n * if (brep) {\n * const vertexCount = await snaptrude.core.geom.query.brep.getVertexCount(brep)\n * }\n * ```\n */\n public abstract getVertexCount(brep: BrepHandle): PluginApiReturn<number>\n\n /**\n * Get the number of half-edges in a brep.\n * @param brep The brep to query\n * @returns The half-edge count as a `number`\n *\n * # Example\n * ```ts\n * const [mass] = await snaptrude.design.query.listMasses()\n * const brep = await snaptrude.design.query.geometry.getBrep(mass)\n * if (brep) {\n * const halfEdgeCount = await snaptrude.core.geom.query.brep.getHalfEdgeCount(brep)\n * }\n * ```\n */\n public abstract getHalfEdgeCount(brep: BrepHandle): PluginApiReturn<number>\n\n /**\n * Get the axis-aligned bounding box of a brep.\n * @param brep The brep to query\n * @returns The bounding box as {@linkcode BBoxComponents}\n *\n * @examplePrompt What is the bounding box of this shape?\n * @examplePrompt How big is this object overall — give me its min and max extents\n *\n * # Example\n * ```ts\n * const [mass] = await snaptrude.design.query.listMasses()\n * const brep = await snaptrude.design.query.geometry.getBrep(mass)\n * if (brep) {\n * const { min, max } = await snaptrude.core.geom.query.brep.getBoundingBox(brep)\n * console.log(\"size:\", max.x - min.x, max.y - min.y, max.z - min.z)\n * }\n * ```\n */\n public abstract getBoundingBox(brep: BrepHandle): PluginApiReturn<BBoxComponents>\n\n /**\n * Test whether two breps are geometrically equal.\n * @param brepA First brep\n * @param brepB Second brep\n * @returns `true` if the breps are equal, otherwise `false`\n *\n * @examplePrompt Are these two shapes geometrically identical?\n * @examplePrompt Check whether these two objects have the same geometry\n *\n * # Example\n * ```ts\n * const [a, b] = await snaptrude.design.query.listMasses()\n * const brepA = await snaptrude.design.query.geometry.getBrep(a)\n * const brepB = await snaptrude.design.query.geometry.getBrep(b)\n * if (brepA && brepB) {\n * const same = await snaptrude.core.geom.query.brep.isEqual(brepA, brepB)\n * }\n * ```\n */\n public abstract isEqual(brepA: BrepHandle, brepB: BrepHandle): PluginApiReturn<boolean>\n}\n\nconst brepArg = z.object({ brep: BrepHandle })\nconst brepEdgeArg = z.object({\n brep: BrepHandle,\n vertexIndexA: z.number(),\n vertexIndexB: z.number(),\n})\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.listFaces}. `{ brep: BrepHandle }` */\nexport const PluginGeomQueryBrepListFacesArgs = brepArg\nexport type PluginGeomQueryBrepListFacesArgs = z.infer<typeof PluginGeomQueryBrepListFacesArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.listEdges}. `{ brep: BrepHandle }` */\nexport const PluginGeomQueryBrepListEdgesArgs = brepArg\nexport type PluginGeomQueryBrepListEdgesArgs = z.infer<typeof PluginGeomQueryBrepListEdgesArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.listVertices}. `{ brep: BrepHandle }` */\nexport const PluginGeomQueryBrepListVerticesArgs = brepArg\nexport type PluginGeomQueryBrepListVerticesArgs = z.infer<typeof PluginGeomQueryBrepListVerticesArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.listHalfEdges}. `{ brep: BrepHandle }` */\nexport const PluginGeomQueryBrepListHalfEdgesArgs = brepArg\nexport type PluginGeomQueryBrepListHalfEdgesArgs = z.infer<\n typeof PluginGeomQueryBrepListHalfEdgesArgs\n>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryBrepApi.getEdge}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `brep` | {@linkcode BrepHandle} | The brep to query |\n * | `vertexIndexA` | `number` | First vertex index |\n * | `vertexIndexB` | `number` | Second vertex index |\n */\nexport const PluginGeomQueryBrepGetEdgeArgs = brepEdgeArg\nexport type PluginGeomQueryBrepGetEdgeArgs = z.infer<typeof PluginGeomQueryBrepGetEdgeArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.hasEdge}. `{ brep, vertexIndexA, vertexIndexB }` */\nexport const PluginGeomQueryBrepHasEdgeArgs = brepEdgeArg\nexport type PluginGeomQueryBrepHasEdgeArgs = z.infer<typeof PluginGeomQueryBrepHasEdgeArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.listEdgesBetween}. `{ brep, vertexIndexA, vertexIndexB }` */\nexport const PluginGeomQueryBrepListEdgesBetweenArgs = brepEdgeArg\nexport type PluginGeomQueryBrepListEdgesBetweenArgs = z.infer<\n typeof PluginGeomQueryBrepListEdgesBetweenArgs\n>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryBrepApi.getVertexPosition}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `brep` | {@linkcode BrepHandle} | The brep to query |\n * | `vertex` | {@linkcode VertexHandle} | The vertex whose position to read |\n */\nexport const PluginGeomQueryBrepGetVertexPositionArgs = z.object({\n brep: BrepHandle,\n vertex: VertexHandle,\n})\nexport type PluginGeomQueryBrepGetVertexPositionArgs = z.infer<\n typeof PluginGeomQueryBrepGetVertexPositionArgs\n>\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.listVertexPositions}. `{ brep: BrepHandle }` */\nexport const PluginGeomQueryBrepListVertexPositionsArgs = brepArg\nexport type PluginGeomQueryBrepListVertexPositionsArgs = z.infer<\n typeof PluginGeomQueryBrepListVertexPositionsArgs\n>\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.getCentroid}. `{ brep: BrepHandle }` */\nexport const PluginGeomQueryBrepGetCentroidArgs = brepArg\nexport type PluginGeomQueryBrepGetCentroidArgs = z.infer<typeof PluginGeomQueryBrepGetCentroidArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.getFaceCount}. `{ brep: BrepHandle }` */\nexport const PluginGeomQueryBrepGetFaceCountArgs = brepArg\nexport type PluginGeomQueryBrepGetFaceCountArgs = z.infer<typeof PluginGeomQueryBrepGetFaceCountArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.getEdgeCount}. `{ brep: BrepHandle }` */\nexport const PluginGeomQueryBrepGetEdgeCountArgs = brepArg\nexport type PluginGeomQueryBrepGetEdgeCountArgs = z.infer<typeof PluginGeomQueryBrepGetEdgeCountArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.getVertexCount}. `{ brep: BrepHandle }` */\nexport const PluginGeomQueryBrepGetVertexCountArgs = brepArg\nexport type PluginGeomQueryBrepGetVertexCountArgs = z.infer<\n typeof PluginGeomQueryBrepGetVertexCountArgs\n>\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.getHalfEdgeCount}. `{ brep: BrepHandle }` */\nexport const PluginGeomQueryBrepGetHalfEdgeCountArgs = brepArg\nexport type PluginGeomQueryBrepGetHalfEdgeCountArgs = z.infer<\n typeof PluginGeomQueryBrepGetHalfEdgeCountArgs\n>\n\n/** Arguments for {@linkcode PluginGeomQueryBrepApi.getBoundingBox}. `{ brep: BrepHandle }` */\nexport const PluginGeomQueryBrepGetBoundingBoxArgs = brepArg\nexport type PluginGeomQueryBrepGetBoundingBoxArgs = z.infer<\n typeof PluginGeomQueryBrepGetBoundingBoxArgs\n>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryBrepApi.isEqual}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `brepA` | {@linkcode BrepHandle} | First brep |\n * | `brepB` | {@linkcode BrepHandle} | Second brep |\n */\nexport const PluginGeomQueryBrepIsEqualArgs = z.object({\n brepA: BrepHandle,\n brepB: BrepHandle,\n})\nexport type PluginGeomQueryBrepIsEqualArgs = z.infer<typeof PluginGeomQueryBrepIsEqualArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport {\n BrepHandle,\n FaceHandle,\n EdgeHandle,\n VertexHandle,\n HalfEdgeHandle,\n Vec3Components,\n} from \"../../../../handles\"\n\n/**\n * Face queries — read the topology and boundary geometry of a single BREP face\n * (all-handle model, §11). A {@linkcode FaceHandle} is minted by walking from a\n * {@linkcode BrepHandle}; it is session-ephemeral and goes stale on\n * undo/redo/re-topologize.\n *\n * Traversals mint fresh child topology handles; position reads return\n * {@linkcode Vec3Components}. Holes are modelled per-loop: {@linkcode PluginGeomQueryFaceApi.listHoles}\n * returns one seed half-edge per hole, and {@linkcode PluginGeomQueryFaceApi.listHoleHalfEdges}\n * returns the full (flat) half-edge loop of one hole by index. No query mutates its inputs.\n *\n * Accessed via `snaptrude.core.geom.query.face`.\n */\nexport abstract class PluginGeomQueryFaceApi {\n constructor() {}\n\n /**\n * Get the index of a face within its brep.\n * @param face The face to query\n * @returns The index as a `number` (`-1` if unindexed)\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const index = await snaptrude.core.geom.query.face.getIndex(face)\n * }\n * ```\n */\n public abstract getIndex(face: FaceHandle): PluginApiReturn<number>\n\n /**\n * Get the raw (unmapped) material index of a face.\n * @param face The face to query\n * @returns The material index as a `number`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const materialIndex = await snaptrude.core.geom.query.face.getMaterialIndex(face)\n * }\n * ```\n */\n public abstract getMaterialIndex(face: FaceHandle): PluginApiReturn<number>\n\n /**\n * Get a seed half-edge of a face's outer loop.\n * @param face The face to query\n * @returns The half-edge as a {@linkcode HalfEdgeHandle}, or `null` for a degenerate face\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const seed = await snaptrude.core.geom.query.face.getHalfEdge(face)\n * if (seed) {\n * const next = await snaptrude.core.geom.query.halfedge.getNext(seed)\n * }\n * }\n * ```\n */\n public abstract getHalfEdge(face: FaceHandle): PluginApiReturn<HalfEdgeHandle | null>\n\n /**\n * List the edges of a face's outer loop.\n * @param face The face to query\n * @returns The edges as {@linkcode EdgeHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const edges = await snaptrude.core.geom.query.face.listEdges(face)\n * }\n * ```\n */\n public abstract listEdges(face: FaceHandle): PluginApiReturn<EdgeHandle[]>\n\n /**\n * List the half-edges of a face's outer loop.\n * @param face The face to query\n * @returns The half-edges as {@linkcode HalfEdgeHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const halfEdges = await snaptrude.core.geom.query.face.listHalfEdges(face)\n * }\n * ```\n */\n public abstract listHalfEdges(face: FaceHandle): PluginApiReturn<HalfEdgeHandle[]>\n\n /**\n * List the vertices of a face's outer loop.\n * @param face The face to query\n * @returns The vertices as {@linkcode VertexHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const vertices = await snaptrude.core.geom.query.face.listVertices(face)\n * }\n * ```\n */\n public abstract listVertices(face: FaceHandle): PluginApiReturn<VertexHandle[]>\n\n /**\n * List a face's holes as one seed half-edge per hole loop.\n * @param face The face to query\n * @returns The hole seeds as {@linkcode HalfEdgeHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const holeSeeds = await snaptrude.core.geom.query.face.listHoles(face)\n * console.log(\"holes in this face:\", holeSeeds.length)\n * }\n * ```\n */\n public abstract listHoles(face: FaceHandle): PluginApiReturn<HalfEdgeHandle[]>\n\n /**\n * Get the number of holes in a face.\n * @param face The face to query\n * @returns The hole count as a `number`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const holeCount = await snaptrude.core.geom.query.face.getHoleCount(face)\n * }\n * ```\n */\n public abstract getHoleCount(face: FaceHandle): PluginApiReturn<number>\n\n /**\n * List the half-edge loop of one hole of a face (by hole index).\n * @param face The face to query\n * @param holeIndex Index of the hole (`0..getHoleCount-1`)\n * @returns The hole's half-edges as {@linkcode HalfEdgeHandle}`[]` (`[]` if the index is out of range)\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const holeCount = await snaptrude.core.geom.query.face.getHoleCount(face)\n * if (holeCount > 0) {\n * const loop = await snaptrude.core.geom.query.face.listHoleHalfEdges(face, 0)\n * }\n * }\n * ```\n */\n public abstract listHoleHalfEdges(\n face: FaceHandle,\n holeIndex: number,\n ): PluginApiReturn<HalfEdgeHandle[]>\n\n /**\n * Test whether a face has any holes.\n * @param face The face to query\n * @returns `true` if the face has at least one hole, otherwise `false`\n *\n * @examplePrompt Does this face have any holes cut into it?\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const pierced = await snaptrude.core.geom.query.face.hasHoles(face)\n * }\n * ```\n */\n public abstract hasHoles(face: FaceHandle): PluginApiReturn<boolean>\n\n /**\n * Get the seed half-edge of the hole loop containing a given half-edge.\n * @param face The face to query\n * @param halfEdge The half-edge to locate\n * @returns The hole seed as a {@linkcode HalfEdgeHandle}, or `null` if not in any hole\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const [he] = await snaptrude.core.geom.query.face.listHoleHalfEdges(face, 0)\n * if (he) {\n * const seed = await snaptrude.core.geom.query.face.getHoleContainingHalfEdge(face, he)\n * }\n * }\n * ```\n */\n public abstract getHoleContainingHalfEdge(\n face: FaceHandle,\n halfEdge: HalfEdgeHandle,\n ): PluginApiReturn<HalfEdgeHandle | null>\n\n /**\n * List the positions of a face's outer-loop vertices (needs the parent brep for coordinates).\n * @param face The face to query\n * @param brep The parent brep (source of vertex coordinates)\n * @returns The positions as {@linkcode Vec3Components}`[]`\n *\n * @examplePrompt What are the corner coordinates of this face?\n * @examplePrompt Get the boundary points of the selected face\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const corners = await snaptrude.core.geom.query.face.listVertexPositions(face, brep)\n * for (const p of corners) console.log(p.x, p.y, p.z)\n * }\n * ```\n */\n public abstract listVertexPositions(\n face: FaceHandle,\n brep: BrepHandle,\n ): PluginApiReturn<Vec3Components[]>\n\n /**\n * List the tessellated boundary points of a face's outer loop (arcs sampled,\n * sense-corrected). Not cardinality-equal to {@linkcode PluginGeomQueryFaceApi.listVertexPositions}.\n * @param face The face to query\n * @returns The boundary points as {@linkcode Vec3Components}`[]`\n *\n * @examplePrompt Trace the outline of this face including its curved edges\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const outline = await snaptrude.core.geom.query.face.listVertexPositionsWithCurves(face)\n * }\n * ```\n */\n public abstract listVertexPositionsWithCurves(\n face: FaceHandle,\n ): PluginApiReturn<Vec3Components[]>\n\n /**\n * List the faces adjacent to a face (sharing an edge). Boundary edges are skipped.\n * @param face The face to query\n * @returns The adjacent faces as {@linkcode FaceHandle}`[]`\n *\n * @examplePrompt Which faces are next to this one?\n * @examplePrompt Find the faces that share an edge with the selected face\n *\n * # Example\n * ```ts\n * const [mass] = await snaptrude.design.query.listMasses()\n * const brep = await snaptrude.design.query.geometry.getBrep(mass)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const neighbours = await snaptrude.core.geom.query.face.listAdjacentFaces(face)\n * }\n * ```\n */\n public abstract listAdjacentFaces(face: FaceHandle): PluginApiReturn<FaceHandle[]>\n}\n\nconst faceArg = z.object({ face: FaceHandle })\n\n/** Arguments for {@linkcode PluginGeomQueryFaceApi.getIndex}. `{ face: FaceHandle }` */\nexport const PluginGeomQueryFaceGetIndexArgs = faceArg\nexport type PluginGeomQueryFaceGetIndexArgs = z.infer<typeof PluginGeomQueryFaceGetIndexArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryFaceApi.getMaterialIndex}. `{ face: FaceHandle }` */\nexport const PluginGeomQueryFaceGetMaterialIndexArgs = faceArg\nexport type PluginGeomQueryFaceGetMaterialIndexArgs = z.infer<\n typeof PluginGeomQueryFaceGetMaterialIndexArgs\n>\n\n/** Arguments for {@linkcode PluginGeomQueryFaceApi.getHalfEdge}. `{ face: FaceHandle }` */\nexport const PluginGeomQueryFaceGetHalfEdgeArgs = faceArg\nexport type PluginGeomQueryFaceGetHalfEdgeArgs = z.infer<typeof PluginGeomQueryFaceGetHalfEdgeArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryFaceApi.listEdges}. `{ face: FaceHandle }` */\nexport const PluginGeomQueryFaceListEdgesArgs = faceArg\nexport type PluginGeomQueryFaceListEdgesArgs = z.infer<typeof PluginGeomQueryFaceListEdgesArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryFaceApi.listHalfEdges}. `{ face: FaceHandle }` */\nexport const PluginGeomQueryFaceListHalfEdgesArgs = faceArg\nexport type PluginGeomQueryFaceListHalfEdgesArgs = z.infer<\n typeof PluginGeomQueryFaceListHalfEdgesArgs\n>\n\n/** Arguments for {@linkcode PluginGeomQueryFaceApi.listVertices}. `{ face: FaceHandle }` */\nexport const PluginGeomQueryFaceListVerticesArgs = faceArg\nexport type PluginGeomQueryFaceListVerticesArgs = z.infer<typeof PluginGeomQueryFaceListVerticesArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryFaceApi.listHoles}. `{ face: FaceHandle }` */\nexport const PluginGeomQueryFaceListHolesArgs = faceArg\nexport type PluginGeomQueryFaceListHolesArgs = z.infer<typeof PluginGeomQueryFaceListHolesArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryFaceApi.getHoleCount}. `{ face: FaceHandle }` */\nexport const PluginGeomQueryFaceGetHoleCountArgs = faceArg\nexport type PluginGeomQueryFaceGetHoleCountArgs = z.infer<typeof PluginGeomQueryFaceGetHoleCountArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryFaceApi.listHoleHalfEdges}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `face` | {@linkcode FaceHandle} | The face to query |\n * | `holeIndex` | `number` | Index of the hole (`0..getHoleCount-1`) |\n */\nexport const PluginGeomQueryFaceListHoleHalfEdgesArgs = z.object({\n face: FaceHandle,\n holeIndex: z.number(),\n})\nexport type PluginGeomQueryFaceListHoleHalfEdgesArgs = z.infer<\n typeof PluginGeomQueryFaceListHoleHalfEdgesArgs\n>\n\n/** Arguments for {@linkcode PluginGeomQueryFaceApi.hasHoles}. `{ face: FaceHandle }` */\nexport const PluginGeomQueryFaceHasHolesArgs = faceArg\nexport type PluginGeomQueryFaceHasHolesArgs = z.infer<typeof PluginGeomQueryFaceHasHolesArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryFaceApi.getHoleContainingHalfEdge}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `face` | {@linkcode FaceHandle} | The face to query |\n * | `halfEdge` | {@linkcode HalfEdgeHandle} | The half-edge to locate |\n */\nexport const PluginGeomQueryFaceGetHoleContainingHalfEdgeArgs = z.object({\n face: FaceHandle,\n halfEdge: HalfEdgeHandle,\n})\nexport type PluginGeomQueryFaceGetHoleContainingHalfEdgeArgs = z.infer<\n typeof PluginGeomQueryFaceGetHoleContainingHalfEdgeArgs\n>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryFaceApi.listVertexPositions}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `face` | {@linkcode FaceHandle} | The face to query |\n * | `brep` | {@linkcode BrepHandle} | The parent brep (source of vertex coordinates) |\n */\nexport const PluginGeomQueryFaceListVertexPositionsArgs = z.object({\n face: FaceHandle,\n brep: BrepHandle,\n})\nexport type PluginGeomQueryFaceListVertexPositionsArgs = z.infer<\n typeof PluginGeomQueryFaceListVertexPositionsArgs\n>\n\n/** Arguments for {@linkcode PluginGeomQueryFaceApi.listVertexPositionsWithCurves}. `{ face: FaceHandle }` */\nexport const PluginGeomQueryFaceListVertexPositionsWithCurvesArgs = faceArg\nexport type PluginGeomQueryFaceListVertexPositionsWithCurvesArgs = z.infer<\n typeof PluginGeomQueryFaceListVertexPositionsWithCurvesArgs\n>\n\n/** Arguments for {@linkcode PluginGeomQueryFaceApi.listAdjacentFaces}. `{ face: FaceHandle }` */\nexport const PluginGeomQueryFaceListAdjacentFacesArgs = faceArg\nexport type PluginGeomQueryFaceListAdjacentFacesArgs = z.infer<\n typeof PluginGeomQueryFaceListAdjacentFacesArgs\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport { EdgeHandle, VertexHandle, HalfEdgeHandle, FaceHandle, CurveHandle } from \"../../../../handles\"\n\n/**\n * Edge queries — read a single BREP edge's topology and geometry (all-handle model,\n * §11). An {@linkcode EdgeHandle} is minted by walking from a brep/face/vertex handle;\n * it is session-ephemeral and goes stale on undo/redo/re-topologize.\n *\n * Accessed via `snaptrude.core.geom.query.edge`.\n */\nexport abstract class PluginGeomQueryEdgeApi {\n constructor() {}\n\n /**\n * Get the index of an edge within its brep.\n * @param edge The edge to query\n * @returns The index as a `number` (`-1` if unindexed)\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [edge] = await snaptrude.core.geom.query.brep.listEdges(brep)\n * const index = await snaptrude.core.geom.query.edge.getIndex(edge)\n * }\n * ```\n */\n public abstract getIndex(edge: EdgeHandle): PluginApiReturn<number>\n\n /**\n * Get the primary half-edge of an edge.\n * @param edge The edge to query\n * @returns The half-edge as a {@linkcode HalfEdgeHandle}, or `null` if uninitialized\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [edge] = await snaptrude.core.geom.query.brep.listEdges(brep)\n * const halfEdge = await snaptrude.core.geom.query.edge.getHalfEdge(edge)\n * if (halfEdge) {\n * const face = await snaptrude.core.geom.query.halfedge.getFace(halfEdge)\n * }\n * }\n * ```\n */\n public abstract getHalfEdge(edge: EdgeHandle): PluginApiReturn<HalfEdgeHandle | null>\n\n /**\n * List the two endpoint vertices of an edge.\n * @param edge The edge to query\n * @returns The endpoints as {@linkcode VertexHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [edge] = await snaptrude.core.geom.query.brep.listEdges(brep)\n * const [a, b] = await snaptrude.core.geom.query.edge.listVertices(edge)\n * const start = await snaptrude.core.geom.query.vertex.getPosition(brep, a)\n * const end = await snaptrude.core.geom.query.vertex.getPosition(brep, b)\n * }\n * ```\n */\n public abstract listVertices(edge: EdgeHandle): PluginApiReturn<VertexHandle[]>\n\n /**\n * Get the underlying curve geometry of an edge (a line or arc).\n * @param edge The edge to query\n * @returns The curve as a {@linkcode CurveHandle}, or `null` if it is a circle or unset\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [edge] = await snaptrude.core.geom.query.brep.listEdges(brep)\n * const curve = await snaptrude.core.geom.query.edge.getCurve(edge)\n * if (curve) {\n * const length = await snaptrude.core.geom.query.curve.getLength(curve)\n * }\n * }\n * ```\n */\n public abstract getCurve(edge: EdgeHandle): PluginApiReturn<CurveHandle | null>\n\n /**\n * List the faces bordering an edge (one or two).\n * @param edge The edge to query\n * @returns The bordering faces as {@linkcode FaceHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [edge] = await snaptrude.core.geom.query.brep.listEdges(brep)\n * const faces = await snaptrude.core.geom.query.edge.listFaces(edge)\n * console.log(faces.length === 1 ? \"boundary edge\" : \"interior edge\")\n * }\n * ```\n */\n public abstract listFaces(edge: EdgeHandle): PluginApiReturn<FaceHandle[]>\n}\n\nconst edgeArg = z.object({ edge: EdgeHandle })\n\n/** Arguments for {@linkcode PluginGeomQueryEdgeApi.getIndex}. `{ edge: EdgeHandle }` */\nexport const PluginGeomQueryEdgeGetIndexArgs = edgeArg\nexport type PluginGeomQueryEdgeGetIndexArgs = z.infer<typeof PluginGeomQueryEdgeGetIndexArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryEdgeApi.getHalfEdge}. `{ edge: EdgeHandle }` */\nexport const PluginGeomQueryEdgeGetHalfEdgeArgs = edgeArg\nexport type PluginGeomQueryEdgeGetHalfEdgeArgs = z.infer<typeof PluginGeomQueryEdgeGetHalfEdgeArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryEdgeApi.listVertices}. `{ edge: EdgeHandle }` */\nexport const PluginGeomQueryEdgeListVerticesArgs = edgeArg\nexport type PluginGeomQueryEdgeListVerticesArgs = z.infer<typeof PluginGeomQueryEdgeListVerticesArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryEdgeApi.getCurve}. `{ edge: EdgeHandle }` */\nexport const PluginGeomQueryEdgeGetCurveArgs = edgeArg\nexport type PluginGeomQueryEdgeGetCurveArgs = z.infer<typeof PluginGeomQueryEdgeGetCurveArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryEdgeApi.listFaces}. `{ edge: EdgeHandle }` */\nexport const PluginGeomQueryEdgeListFacesArgs = edgeArg\nexport type PluginGeomQueryEdgeListFacesArgs = z.infer<typeof PluginGeomQueryEdgeListFacesArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport { HalfEdgeHandle, VertexHandle, EdgeHandle, FaceHandle } from \"../../../../handles\"\n\n/**\n * Half-edge queries — walk and read a single BREP half-edge (all-handle model, §11).\n * A {@linkcode HalfEdgeHandle} is minted by walking from a brep/face/edge/vertex\n * handle; it is session-ephemeral and goes stale on undo/redo/re-topologize.\n *\n * The kind token is all-lowercase `\"halfedge\"` (§6.1 — no camelCase namespaces).\n * Traversals (`getNext`/`getPrev`/`getFlip`) return `null` on a boundary or a\n * malformed chain rather than throwing (§6, reads never throw).\n *\n * Accessed via `snaptrude.core.geom.query.halfedge`.\n */\nexport abstract class PluginGeomQueryHalfEdgeApi {\n constructor() {}\n\n /**\n * Get the next half-edge around the face loop.\n * @param halfEdge The half-edge to walk from\n * @returns The next half-edge as a {@linkcode HalfEdgeHandle}, or `null` on a malformed chain\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [face] = await snaptrude.core.geom.query.brep.listFaces(brep)\n * const [he] = await snaptrude.core.geom.query.face.listHalfEdges(face)\n * const next = await snaptrude.core.geom.query.halfedge.getNext(he)\n * if (next) {\n * const vertex = await snaptrude.core.geom.query.halfedge.getVertex(next)\n * }\n * }\n * ```\n */\n public abstract getNext(halfEdge: HalfEdgeHandle): PluginApiReturn<HalfEdgeHandle | null>\n\n /**\n * Get the previous half-edge around the face loop.\n * @param halfEdge The half-edge to walk from\n * @returns The previous half-edge as a {@linkcode HalfEdgeHandle}, or `null` on a malformed chain\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [he] = await snaptrude.core.geom.query.brep.listHalfEdges(brep)\n * const prev = await snaptrude.core.geom.query.halfedge.getPrev(he)\n * if (prev) {\n * const edge = await snaptrude.core.geom.query.halfedge.getEdge(prev)\n * }\n * }\n * ```\n */\n public abstract getPrev(halfEdge: HalfEdgeHandle): PluginApiReturn<HalfEdgeHandle | null>\n\n /**\n * Get the flip (opposite) half-edge of the shared edge.\n * @param halfEdge The half-edge to flip\n * @returns The flip half-edge as a {@linkcode HalfEdgeHandle}, or `null` on a boundary\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [he] = await snaptrude.core.geom.query.brep.listHalfEdges(brep)\n * const flip = await snaptrude.core.geom.query.halfedge.getFlip(he)\n * if (flip) {\n * // cross the shared edge into the neighbouring face\n * const neighbourFace = await snaptrude.core.geom.query.halfedge.getFace(flip)\n * }\n * }\n * ```\n */\n public abstract getFlip(halfEdge: HalfEdgeHandle): PluginApiReturn<HalfEdgeHandle | null>\n\n /**\n * Get the tail vertex of a half-edge.\n * @param halfEdge The half-edge to read\n * @returns The vertex as a {@linkcode VertexHandle}\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [he] = await snaptrude.core.geom.query.brep.listHalfEdges(brep)\n * const vertex = await snaptrude.core.geom.query.halfedge.getVertex(he)\n * const pos = await snaptrude.core.geom.query.vertex.getPosition(brep, vertex)\n * }\n * ```\n */\n public abstract getVertex(halfEdge: HalfEdgeHandle): PluginApiReturn<VertexHandle>\n\n /**\n * Get the edge of a half-edge.\n * @param halfEdge The half-edge to read\n * @returns The edge as an {@linkcode EdgeHandle}\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [he] = await snaptrude.core.geom.query.brep.listHalfEdges(brep)\n * const edge = await snaptrude.core.geom.query.halfedge.getEdge(he)\n * const faces = await snaptrude.core.geom.query.edge.listFaces(edge)\n * }\n * ```\n */\n public abstract getEdge(halfEdge: HalfEdgeHandle): PluginApiReturn<EdgeHandle>\n\n /**\n * Get the face of a half-edge.\n * @param halfEdge The half-edge to read\n * @returns The face as a {@linkcode FaceHandle}\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [he] = await snaptrude.core.geom.query.brep.listHalfEdges(brep)\n * const face = await snaptrude.core.geom.query.halfedge.getFace(he)\n * const index = await snaptrude.core.geom.query.face.getIndex(face)\n * }\n * ```\n */\n public abstract getFace(halfEdge: HalfEdgeHandle): PluginApiReturn<FaceHandle>\n\n /**\n * Test whether a half-edge lies on the brep boundary (has no flip).\n * @param halfEdge The half-edge to test\n * @returns `true` if on the boundary, otherwise `false`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const halfEdges = await snaptrude.core.geom.query.brep.listHalfEdges(brep)\n * let boundary = 0\n * for (const he of halfEdges) {\n * if (await snaptrude.core.geom.query.halfedge.isOnBoundary(he)) boundary++\n * }\n * console.log(\"boundary half-edges:\", boundary)\n * }\n * ```\n */\n public abstract isOnBoundary(halfEdge: HalfEdgeHandle): PluginApiReturn<boolean>\n\n /**\n * Test whether a half-edge is the forward (primary) half-edge of its edge —\n * i.e. `edge.getHalfEdge() === thisHalfEdge`.\n * @param halfEdge The half-edge to test\n * @returns `true` if forward, otherwise `false`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [he] = await snaptrude.core.geom.query.brep.listHalfEdges(brep)\n * const forward = await snaptrude.core.geom.query.halfedge.isForward(he)\n * console.log(forward ? \"primary half-edge\" : \"flip half-edge\")\n * }\n * ```\n */\n public abstract isForward(halfEdge: HalfEdgeHandle): PluginApiReturn<boolean>\n}\n\nconst heArg = z.object({ halfEdge: HalfEdgeHandle })\n\n/** Arguments for {@linkcode PluginGeomQueryHalfEdgeApi.getNext}. `{ halfEdge: HalfEdgeHandle }` */\nexport const PluginGeomQueryHalfEdgeGetNextArgs = heArg\nexport type PluginGeomQueryHalfEdgeGetNextArgs = z.infer<typeof PluginGeomQueryHalfEdgeGetNextArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryHalfEdgeApi.getPrev}. `{ halfEdge: HalfEdgeHandle }` */\nexport const PluginGeomQueryHalfEdgeGetPrevArgs = heArg\nexport type PluginGeomQueryHalfEdgeGetPrevArgs = z.infer<typeof PluginGeomQueryHalfEdgeGetPrevArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryHalfEdgeApi.getFlip}. `{ halfEdge: HalfEdgeHandle }` */\nexport const PluginGeomQueryHalfEdgeGetFlipArgs = heArg\nexport type PluginGeomQueryHalfEdgeGetFlipArgs = z.infer<typeof PluginGeomQueryHalfEdgeGetFlipArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryHalfEdgeApi.getVertex}. `{ halfEdge: HalfEdgeHandle }` */\nexport const PluginGeomQueryHalfEdgeGetVertexArgs = heArg\nexport type PluginGeomQueryHalfEdgeGetVertexArgs = z.infer<typeof PluginGeomQueryHalfEdgeGetVertexArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryHalfEdgeApi.getEdge}. `{ halfEdge: HalfEdgeHandle }` */\nexport const PluginGeomQueryHalfEdgeGetEdgeArgs = heArg\nexport type PluginGeomQueryHalfEdgeGetEdgeArgs = z.infer<typeof PluginGeomQueryHalfEdgeGetEdgeArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryHalfEdgeApi.getFace}. `{ halfEdge: HalfEdgeHandle }` */\nexport const PluginGeomQueryHalfEdgeGetFaceArgs = heArg\nexport type PluginGeomQueryHalfEdgeGetFaceArgs = z.infer<typeof PluginGeomQueryHalfEdgeGetFaceArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryHalfEdgeApi.isOnBoundary}. `{ halfEdge: HalfEdgeHandle }` */\nexport const PluginGeomQueryHalfEdgeIsOnBoundaryArgs = heArg\nexport type PluginGeomQueryHalfEdgeIsOnBoundaryArgs = z.infer<\n typeof PluginGeomQueryHalfEdgeIsOnBoundaryArgs\n>\n\n/** Arguments for {@linkcode PluginGeomQueryHalfEdgeApi.isForward}. `{ halfEdge: HalfEdgeHandle }` */\nexport const PluginGeomQueryHalfEdgeIsForwardArgs = heArg\nexport type PluginGeomQueryHalfEdgeIsForwardArgs = z.infer<typeof PluginGeomQueryHalfEdgeIsForwardArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport {\n BrepHandle,\n VertexHandle,\n HalfEdgeHandle,\n EdgeHandle,\n FaceHandle,\n Vec3Components,\n} from \"../../../../handles\"\n\n/**\n * Vertex queries — read a single BREP vertex's topology and position (all-handle\n * model, §11). A {@linkcode VertexHandle} is minted by walking from a brep/face/edge\n * handle; it is session-ephemeral and goes stale on undo/redo/re-topologize.\n *\n * Position lives on the parent brep (indexed by the vertex), so\n * {@linkcode PluginGeomQueryVertexApi.getPosition} takes both handles. No query\n * mutates its inputs.\n *\n * Accessed via `snaptrude.core.geom.query.vertex`.\n */\nexport abstract class PluginGeomQueryVertexApi {\n constructor() {}\n\n /**\n * Get the index of a vertex within its brep.\n * @param vertex The vertex to query\n * @returns The index as a `number` (`-1` if unindexed)\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [vertex] = await snaptrude.core.geom.query.brep.listVertices(brep)\n * const index = await snaptrude.core.geom.query.vertex.getIndex(vertex)\n * }\n * ```\n */\n public abstract getIndex(vertex: VertexHandle): PluginApiReturn<number>\n\n /**\n * Get a seed half-edge emanating from a vertex.\n * @param vertex The vertex to query\n * @returns The half-edge as a {@linkcode HalfEdgeHandle}, or `null` if uninitialized\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [vertex] = await snaptrude.core.geom.query.brep.listVertices(brep)\n * const halfEdge = await snaptrude.core.geom.query.vertex.getHalfEdge(vertex)\n * if (halfEdge) {\n * const edge = await snaptrude.core.geom.query.halfedge.getEdge(halfEdge)\n * }\n * }\n * ```\n */\n public abstract getHalfEdge(vertex: VertexHandle): PluginApiReturn<HalfEdgeHandle | null>\n\n /**\n * Get the position of a vertex (needs the parent brep for coordinates).\n * @param brep The parent brep (source of coordinates)\n * @param vertex The vertex whose position to read\n * @returns The position as {@linkcode Vec3Components}\n *\n * @examplePrompt What are the coordinates of this corner point?\n * @examplePrompt Get the exact x, y, z position of the selected vertex\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [vertex] = await snaptrude.core.geom.query.brep.listVertices(brep)\n * const pos = await snaptrude.core.geom.query.vertex.getPosition(brep, vertex)\n * console.log(pos.x, pos.y, pos.z)\n * }\n * ```\n */\n public abstract getPosition(\n brep: BrepHandle,\n vertex: VertexHandle\n ): PluginApiReturn<Vec3Components>\n\n /**\n * List the half-edges around a vertex.\n * @param vertex The vertex to query\n * @returns The half-edges as {@linkcode HalfEdgeHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [vertex] = await snaptrude.core.geom.query.brep.listVertices(brep)\n * const halfEdges = await snaptrude.core.geom.query.vertex.listHalfEdges(vertex)\n * console.log(\"half-edges at this vertex:\", halfEdges.length)\n * }\n * ```\n */\n public abstract listHalfEdges(vertex: VertexHandle): PluginApiReturn<HalfEdgeHandle[]>\n\n /**\n * List the edges around a vertex.\n * @param vertex The vertex to query\n * @returns The edges as {@linkcode EdgeHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [vertex] = await snaptrude.core.geom.query.brep.listVertices(brep)\n * const edges = await snaptrude.core.geom.query.vertex.listEdges(vertex)\n * console.log(\"edges meeting at this corner:\", edges.length)\n * }\n * ```\n */\n public abstract listEdges(vertex: VertexHandle): PluginApiReturn<EdgeHandle[]>\n\n /**\n * List the faces around a vertex.\n * @param vertex The vertex to query\n * @returns The faces as {@linkcode FaceHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [vertex] = await snaptrude.core.geom.query.brep.listVertices(brep)\n * const faces = await snaptrude.core.geom.query.vertex.listFaces(vertex)\n * console.log(\"faces sharing this corner:\", faces.length)\n * }\n * ```\n */\n public abstract listFaces(vertex: VertexHandle): PluginApiReturn<FaceHandle[]>\n\n /**\n * List the neighbouring vertices of a vertex.\n * @param vertex The vertex to query\n * @returns The neighbours as {@linkcode VertexHandle}`[]`\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const brep = await snaptrude.design.query.geometry.getBrep(wall)\n * if (brep) {\n * const [vertex] = await snaptrude.core.geom.query.brep.listVertices(brep)\n * const neighbors = await snaptrude.core.geom.query.vertex.listNeighbors(vertex)\n * for (const n of neighbors) {\n * const pos = await snaptrude.core.geom.query.vertex.getPosition(brep, n)\n * }\n * }\n * ```\n */\n public abstract listNeighbors(vertex: VertexHandle): PluginApiReturn<VertexHandle[]>\n}\n\nconst vertexArg = z.object({ vertex: VertexHandle })\n\n/** Arguments for {@linkcode PluginGeomQueryVertexApi.getIndex}. `{ vertex: VertexHandle }` */\nexport const PluginGeomQueryVertexGetIndexArgs = vertexArg\nexport type PluginGeomQueryVertexGetIndexArgs = z.infer<typeof PluginGeomQueryVertexGetIndexArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryVertexApi.getHalfEdge}. `{ vertex: VertexHandle }` */\nexport const PluginGeomQueryVertexGetHalfEdgeArgs = vertexArg\nexport type PluginGeomQueryVertexGetHalfEdgeArgs = z.infer<typeof PluginGeomQueryVertexGetHalfEdgeArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomQueryVertexApi.getPosition}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `brep` | {@linkcode BrepHandle} | The parent brep (source of coordinates) |\n * | `vertex` | {@linkcode VertexHandle} | The vertex whose position to read |\n */\nexport const PluginGeomQueryVertexGetPositionArgs = z.object({\n brep: BrepHandle,\n vertex: VertexHandle,\n})\nexport type PluginGeomQueryVertexGetPositionArgs = z.infer<typeof PluginGeomQueryVertexGetPositionArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryVertexApi.listHalfEdges}. `{ vertex: VertexHandle }` */\nexport const PluginGeomQueryVertexListHalfEdgesArgs = vertexArg\nexport type PluginGeomQueryVertexListHalfEdgesArgs = z.infer<\n typeof PluginGeomQueryVertexListHalfEdgesArgs\n>\n\n/** Arguments for {@linkcode PluginGeomQueryVertexApi.listEdges}. `{ vertex: VertexHandle }` */\nexport const PluginGeomQueryVertexListEdgesArgs = vertexArg\nexport type PluginGeomQueryVertexListEdgesArgs = z.infer<typeof PluginGeomQueryVertexListEdgesArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryVertexApi.listFaces}. `{ vertex: VertexHandle }` */\nexport const PluginGeomQueryVertexListFacesArgs = vertexArg\nexport type PluginGeomQueryVertexListFacesArgs = z.infer<typeof PluginGeomQueryVertexListFacesArgs>\n\n/** Arguments for {@linkcode PluginGeomQueryVertexApi.listNeighbors}. `{ vertex: VertexHandle }` */\nexport const PluginGeomQueryVertexListNeighborsArgs = vertexArg\nexport type PluginGeomQueryVertexListNeighborsArgs = z.infer<\n typeof PluginGeomQueryVertexListNeighborsArgs\n>\n","import { PluginGeomQueryCurveApi } from \"./curve\"\nimport { PluginGeomQueryArcApi } from \"./arc\"\nimport { PluginGeomQueryCircleApi } from \"./circle\"\nimport { PluginGeomQueryProfileApi } from \"./profile\"\nimport { PluginGeomQueryContourApi } from \"./contour\"\nimport { PluginGeomQueryBrepApi } from \"./brep\"\nimport { PluginGeomQueryFaceApi } from \"./face\"\nimport { PluginGeomQueryEdgeApi } from \"./edge\"\nimport { PluginGeomQueryHalfEdgeApi } from \"./halfedge\"\nimport { PluginGeomQueryVertexApi } from \"./vertex\"\n\n/**\n * Geometry-kernel query namespace — read geometry, topology, and relationships as\n * plain values / child handles (all-handle model, §11). No query mutates its inputs.\n *\n * - {@linkcode PluginGeomQueryApi.curve} — shared line/arc queries + two-curve relationships\n * - {@linkcode PluginGeomQueryApi.arc} — arc-specific reads\n * - {@linkcode PluginGeomQueryApi.circle} — circle-specific reads\n * - {@linkcode PluginGeomQueryApi.profile} — profile reads\n * - {@linkcode PluginGeomQueryApi.contour} — contour reads (outer profile + holes)\n * - {@linkcode PluginGeomQueryApi.brep} — BREP mesh topology + geometry\n * - {@linkcode PluginGeomQueryApi.face} — BREP face reads\n * - {@linkcode PluginGeomQueryApi.edge} — BREP edge reads\n * - {@linkcode PluginGeomQueryApi.halfedge} — BREP half-edge walks\n * - {@linkcode PluginGeomQueryApi.vertex} — BREP vertex reads\n *\n * Accessed via `snaptrude.core.geom.query`.\n */\nexport abstract class PluginGeomQueryApi {\n /** Shared curve queries (line or arc) and relationships. See {@linkcode PluginGeomQueryCurveApi}. */\n public abstract curve: PluginGeomQueryCurveApi\n /** Arc-specific queries. See {@linkcode PluginGeomQueryArcApi}. */\n public abstract arc: PluginGeomQueryArcApi\n /** Circle-specific queries. See {@linkcode PluginGeomQueryCircleApi}. */\n public abstract circle: PluginGeomQueryCircleApi\n /** Profile queries. See {@linkcode PluginGeomQueryProfileApi}. */\n public abstract profile: PluginGeomQueryProfileApi\n /** Contour queries. See {@linkcode PluginGeomQueryContourApi}. */\n public abstract contour: PluginGeomQueryContourApi\n /** BREP mesh topology + geometry queries. See {@linkcode PluginGeomQueryBrepApi}. */\n public abstract brep: PluginGeomQueryBrepApi\n /** BREP face queries. See {@linkcode PluginGeomQueryFaceApi}. */\n public abstract face: PluginGeomQueryFaceApi\n /** BREP edge queries. See {@linkcode PluginGeomQueryEdgeApi}. */\n public abstract edge: PluginGeomQueryEdgeApi\n /** BREP half-edge walks. See {@linkcode PluginGeomQueryHalfEdgeApi}. */\n public abstract halfedge: PluginGeomQueryHalfEdgeApi\n /** BREP vertex queries. See {@linkcode PluginGeomQueryVertexApi}. */\n public abstract vertex: PluginGeomQueryVertexApi\n\n constructor() {}\n}\n\nexport * from \"./curve\"\nexport * from \"./arc\"\nexport * from \"./circle\"\nexport * from \"./profile\"\nexport * from \"./contour\"\nexport * from \"./brep\"\nexport * from \"./face\"\nexport * from \"./edge\"\nexport * from \"./halfedge\"\nexport * from \"./vertex\"\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport { Vec3Handle, CurveHandle } from \"../../../../handles\"\n\n/**\n * Curve editing — produce NEW curves from an existing one (all-handle model, §11).\n *\n * Every method takes an opaque {@linkcode CurveHandle} and returns a fresh handle\n * (or handles) for the resulting geometry; the input curve is never mutated. Read\n * the resulting geometry back as plain values with the query namespace.\n *\n * Accessed via `snaptrude.core.geom.update.curve`.\n */\nexport abstract class PluginGeomUpdateCurveApi {\n constructor() {}\n\n /**\n * Extend a curve by a distance from one of its ends. Host API call — returns a handle.\n *\n * @param curve - The curve to extend\n * @param distance - Distance to extend the curve by\n * @param fromStart - Extend from the start end when `true`, otherwise from the end\n * @returns The extended curve as a {@linkcode CurveHandle}\n *\n * @examplePrompt Extend this line by 1 metre\n * @examplePrompt Lengthen this edge from its start point\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(5, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const longer = await snaptrude.core.geom.update.curve.extend(line, 1, false)\n * const length = await snaptrude.core.geom.query.curve.getLength(longer) // 6\n * ```\n */\n public abstract extend(\n curve: CurveHandle,\n distance: number,\n fromStart: boolean,\n ): PluginApiReturn<CurveHandle>\n\n /**\n * Split a curve at a point into separate segments. Host API call — returns handles.\n *\n * @param curve - The curve to split\n * @param point - Point on the curve to split at\n * @returns The resulting segments as {@linkcode CurveHandle}`[]`\n *\n * @examplePrompt Split this line at its midpoint\n * @examplePrompt Break this edge into two pieces where it meets the gridline\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(6, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const mid = await snaptrude.core.math.vec3.new(3, 0, 0)\n * const [left, right] = await snaptrude.core.geom.update.curve.split(line, mid)\n * ```\n */\n public abstract split(\n curve: CurveHandle,\n point: Vec3Handle,\n ): PluginApiReturn<CurveHandle[]>\n\n /**\n * Trim a curve to the portion between two parameter values. Host API call — returns a handle.\n *\n * @param curve - The curve to trim\n * @param startParam - Start parameter of the portion to keep\n * @param endParam - End parameter of the portion to keep\n * @returns The trimmed curve as a {@linkcode CurveHandle}\n *\n * @examplePrompt Trim this line back to a shorter segment\n * @examplePrompt Keep only the middle portion of this curve\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const middle = await snaptrude.core.geom.update.curve.trim(line, 0.25, 0.75)\n * ```\n */\n public abstract trim(\n curve: CurveHandle,\n startParam: number,\n endParam: number,\n ): PluginApiReturn<CurveHandle>\n\n /**\n * Offset a curve by a translation vector. Host API call — returns a handle.\n *\n * @param curve - The curve to offset\n * @param vector - Translation vector to offset the curve by\n * @returns The offset curve as a {@linkcode CurveHandle}\n *\n * @examplePrompt Offset this line 500mm to the side\n * @examplePrompt Shift this edge over to make a parallel copy\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(8, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const sideways = await snaptrude.core.math.vec3.new(0, 0, 0.5)\n * const parallel = await snaptrude.core.geom.update.curve.offset(line, sideways)\n * ```\n */\n public abstract offset(\n curve: CurveHandle,\n vector: Vec3Handle,\n ): PluginApiReturn<CurveHandle>\n\n /**\n * Reverse the direction of a curve. Host API call — returns a handle.\n *\n * @param curve - The curve to reverse\n * @returns The reversed curve as a {@linkcode CurveHandle}\n *\n * # Example\n * ```ts\n * const a = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const b = await snaptrude.core.math.vec3.new(4, 0, 0)\n * const line = await snaptrude.core.geom.create.line(a, b)\n * const reversed = await snaptrude.core.geom.update.curve.reverse(line)\n * const start = await snaptrude.core.geom.query.curve.getStartPoint(reversed) // { x: 4, y: 0, z: 0 }\n * ```\n */\n public abstract reverse(curve: CurveHandle): PluginApiReturn<CurveHandle>\n}\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateCurveApi.extend}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to extend |\n * | `distance` | `number` | Distance to extend the curve by |\n * | `fromStart` | `boolean` | Extend from the start end when `true`, otherwise from the end |\n */\nexport const PluginGeomUpdateCurveExtendArgs = z.object({\n curve: CurveHandle,\n distance: z.number(),\n fromStart: z.boolean(),\n})\n\nexport type PluginGeomUpdateCurveExtendArgs = z.infer<typeof PluginGeomUpdateCurveExtendArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateCurveApi.split}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to split |\n * | `point` | {@linkcode Vec3Handle} | Point on the curve to split at |\n */\nexport const PluginGeomUpdateCurveSplitArgs = z.object({\n curve: CurveHandle,\n point: Vec3Handle,\n})\n\nexport type PluginGeomUpdateCurveSplitArgs = z.infer<typeof PluginGeomUpdateCurveSplitArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateCurveApi.trim}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to trim |\n * | `startParam` | `number` | Start parameter of the portion to keep |\n * | `endParam` | `number` | End parameter of the portion to keep |\n */\nexport const PluginGeomUpdateCurveTrimArgs = z.object({\n curve: CurveHandle,\n startParam: z.number(),\n endParam: z.number(),\n})\n\nexport type PluginGeomUpdateCurveTrimArgs = z.infer<typeof PluginGeomUpdateCurveTrimArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateCurveApi.offset}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to offset |\n * | `vector` | {@linkcode Vec3Handle} | Translation vector to offset the curve by |\n */\nexport const PluginGeomUpdateCurveOffsetArgs = z.object({\n curve: CurveHandle,\n vector: Vec3Handle,\n})\n\nexport type PluginGeomUpdateCurveOffsetArgs = z.infer<typeof PluginGeomUpdateCurveOffsetArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateCurveApi.reverse}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `curve` | {@linkcode CurveHandle} | The curve to reverse |\n */\nexport const PluginGeomUpdateCurveReverseArgs = z.object({\n curve: CurveHandle,\n})\n\nexport type PluginGeomUpdateCurveReverseArgs = z.infer<typeof PluginGeomUpdateCurveReverseArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport {\n ProfileHandle,\n Vec3Handle,\n CurveHandle,\n Vec3Components,\n} from \"../../../../handles\"\n\n/**\n * Profile editing — produce NEW profiles from an existing one (all-handle model, §11).\n *\n * Every method is an immutable derive-new operation: it takes an opaque\n * {@linkcode ProfileHandle} (plus any extra inputs) and returns a fresh\n * {@linkcode ProfileHandle} for the resulting profile. The input profile is never\n * mutated — the original handle keeps referring to the unchanged profile. Read the\n * resulting geometry back as plain values with the query namespace.\n *\n * Accessed via `snaptrude.core.geom.update.profile`.\n */\nexport abstract class PluginGeomUpdateProfileApi {\n constructor() {}\n\n /**\n * Offset a closed profile inward/outward by a signed distance. Immutable —\n * returns a NEW profile and leaves the input unchanged.\n *\n * @param profile The closed profile to offset\n * @param distance Signed offset distance (outward when positive, inward when negative)\n * @returns The offset profile as a NEW {@linkcode ProfileHandle}\n *\n * @examplePrompt Offset this outline 300mm inward\n * @examplePrompt Inset this boundary by a foot all around\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(10, 8)\n * const inset = await snaptrude.core.geom.update.profile.offset(rect, -0.3)\n * const area = await snaptrude.core.geom.query.profile.getArea(inset)\n * ```\n */\n public abstract offset(\n profile: ProfileHandle,\n distance: number,\n ): PluginApiReturn<ProfileHandle>\n\n /**\n * Translate a profile by a vector. Immutable — returns a NEW profile and leaves\n * the input unchanged.\n *\n * @param profile The profile to move\n * @param translation Translation vector to move the profile by\n * @returns The moved profile as a NEW {@linkcode ProfileHandle}\n *\n * @examplePrompt Move this outline 3 metres along the x axis\n * @examplePrompt Shift this boundary to a new position\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(6, 4)\n * const shift = await snaptrude.core.math.vec3.new(3, 0, 0)\n * const moved = await snaptrude.core.geom.update.profile.move(rect, shift)\n * ```\n */\n public abstract move(\n profile: ProfileHandle,\n translation: Vec3Handle,\n ): PluginApiReturn<ProfileHandle>\n\n /**\n * Rotate a profile about an axis through an optional pivot. Immutable — returns a\n * NEW profile and leaves the input unchanged.\n *\n * @param profile The profile to rotate\n * @param axis Rotation axis direction\n * @param angle Rotation angle in radians\n * @param pivot Optional pivot point to rotate about (defaults to the origin)\n * @returns The rotated profile as a NEW {@linkcode ProfileHandle}\n *\n * @examplePrompt Rotate this outline 30 degrees\n * @examplePrompt Turn this boundary about its centre point\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(6, 4)\n * const axis = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const rotated = await snaptrude.core.geom.update.profile.rotate(rect, axis, Math.PI / 6)\n * ```\n */\n public abstract rotate(\n profile: ProfileHandle,\n axis: Vec3Handle,\n angle: number,\n pivot?: Vec3Handle,\n ): PluginApiReturn<ProfileHandle>\n\n /**\n * Scale a profile uniformly or per-axis about an optional pivot. Immutable —\n * returns a NEW profile and leaves the input unchanged.\n *\n * @param profile The profile to scale\n * @param factor Uniform scale factor, or per-axis factors\n * @param pivot Optional pivot point to scale about (defaults to the origin)\n * @returns The scaled profile as a NEW {@linkcode ProfileHandle}\n *\n * @examplePrompt Scale this outline down to half size\n * @examplePrompt Enlarge this boundary by 50 percent\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(6, 4)\n * const half = await snaptrude.core.geom.update.profile.scale(rect, 0.5)\n * const stretched = await snaptrude.core.geom.update.profile.scale(rect, { x: 2, y: 1, z: 1 })\n * ```\n */\n public abstract scale(\n profile: ProfileHandle,\n factor: number | Vec3Components,\n pivot?: Vec3Handle,\n ): PluginApiReturn<ProfileHandle>\n\n /**\n * Mirror a profile across a plane. Immutable — returns a NEW profile and leaves\n * the input unchanged.\n *\n * @param profile The profile to mirror\n * @param plane Mirror plane defined by a point on it and its normal\n * @returns The mirrored profile as a NEW {@linkcode ProfileHandle}\n *\n * @examplePrompt Mirror this outline across the vertical plane\n * @examplePrompt Flip this boundary to its mirror image\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(6, 4)\n * const point = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const normal = await snaptrude.core.math.vec3.new(1, 0, 0)\n * const mirrored = await snaptrude.core.geom.update.profile.mirror(rect, { point, normal })\n * ```\n */\n public abstract mirror(\n profile: ProfileHandle,\n plane: { point: Vec3Handle; normal: Vec3Handle },\n ): PluginApiReturn<ProfileHandle>\n\n /**\n * Append a curve to the start or end of a profile. The curve must connect to the\n * chosen end. Immutable — returns a NEW profile and leaves the input unchanged.\n *\n * @param profile The profile to append to\n * @param curve The curve to append; it must connect to the chosen end\n * @param position Optional end to append at (defaults to `\"end\"`)\n * @returns The extended profile as a NEW {@linkcode ProfileHandle}\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const open = await snaptrude.core.geom.update.profile.remove(rect, \"end\")\n * const pts = await snaptrude.core.geom.query.profile.listPoints(open)\n * const last = pts[pts.length - 1]\n * const from = await snaptrude.core.math.vec3.new(last.x, last.y, last.z)\n * const to = await snaptrude.core.math.vec3.new(pts[0].x, pts[0].y, pts[0].z)\n * const closer = await snaptrude.core.geom.create.line(from, to)\n * const closed = await snaptrude.core.geom.update.profile.add(open, closer, \"end\")\n * ```\n */\n public abstract add(\n profile: ProfileHandle,\n curve: CurveHandle,\n position?: \"start\" | \"end\",\n ): PluginApiReturn<ProfileHandle>\n\n /**\n * Remove the curve at the start or end of a profile. Immutable — returns a NEW\n * profile and leaves the input unchanged.\n *\n * @param profile The profile to remove a curve from\n * @param position Optional end to remove from (defaults to `\"end\"`)\n * @returns The trimmed profile as a NEW {@linkcode ProfileHandle}\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const open = await snaptrude.core.geom.update.profile.remove(rect, \"end\")\n * const isClosed = await snaptrude.core.geom.query.profile.isClosed(open) // false\n * ```\n */\n public abstract remove(\n profile: ProfileHandle,\n position?: \"start\" | \"end\",\n ): PluginApiReturn<ProfileHandle>\n\n /**\n * Reverse the orientation of a profile. Immutable — returns a NEW profile and\n * leaves the input unchanged.\n *\n * @param profile The profile to reverse\n * @returns The reversed profile as a NEW {@linkcode ProfileHandle}\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const reversed = await snaptrude.core.geom.update.profile.reverse(rect)\n * const clockwise = await snaptrude.core.geom.query.profile.isClockwise(reversed)\n * ```\n */\n public abstract reverse(\n profile: ProfileHandle,\n ): PluginApiReturn<ProfileHandle>\n\n /**\n * Simplify a profile by merging collinear/redundant segments. Immutable —\n * returns a NEW profile and leaves the input unchanged.\n *\n * @param profile The profile to simplify\n * @returns The simplified profile as a NEW {@linkcode ProfileHandle}\n *\n * @examplePrompt Clean up this outline by merging collinear segments\n * @examplePrompt Simplify this polyline and remove redundant points\n *\n * # Example\n * ```ts\n * const p0 = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const p1 = await snaptrude.core.math.vec3.new(2, 0, 0) // collinear with p0 and p2\n * const p2 = await snaptrude.core.math.vec3.new(4, 0, 0)\n * const p3 = await snaptrude.core.math.vec3.new(4, 0, 3)\n * const jagged = await snaptrude.core.geom.create.profileFromLinePoints([p0, p1, p2, p3])\n * const clean = await snaptrude.core.geom.update.profile.simplify(jagged)\n * const curves = await snaptrude.core.geom.query.profile.listCurves(clean) // p0→p2 merged\n * ```\n */\n public abstract simplify(\n profile: ProfileHandle,\n ): PluginApiReturn<ProfileHandle>\n}\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateProfileApi.offset}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The closed profile to offset |\n * | `distance` | `number` | Signed offset distance (outward when positive, inward when negative) |\n */\nexport const PluginGeomUpdateProfileOffsetArgs = z.object({\n profile: ProfileHandle,\n distance: z.number(),\n})\n\nexport type PluginGeomUpdateProfileOffsetArgs = z.infer<typeof PluginGeomUpdateProfileOffsetArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateProfileApi.move}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to move |\n * | `translation` | {@linkcode Vec3Handle} | Translation vector to move the profile by |\n */\nexport const PluginGeomUpdateProfileMoveArgs = z.object({\n profile: ProfileHandle,\n translation: Vec3Handle,\n})\n\nexport type PluginGeomUpdateProfileMoveArgs = z.infer<typeof PluginGeomUpdateProfileMoveArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateProfileApi.rotate}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to rotate |\n * | `axis` | {@linkcode Vec3Handle} | Rotation axis direction |\n * | `angle` | `number` | Rotation angle in radians |\n * | `pivot` | {@linkcode Vec3Handle} | Optional pivot point to rotate about (defaults to the origin) |\n */\nexport const PluginGeomUpdateProfileRotateArgs = z.object({\n profile: ProfileHandle,\n axis: Vec3Handle,\n angle: z.number(),\n pivot: Vec3Handle.optional(),\n})\n\nexport type PluginGeomUpdateProfileRotateArgs = z.infer<typeof PluginGeomUpdateProfileRotateArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateProfileApi.scale}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to scale |\n * | `factor` | `number` \\| {@linkcode Vec3Components} | Uniform scale factor, or per-axis factors |\n * | `pivot` | {@linkcode Vec3Handle} | Optional pivot point to scale about (defaults to the origin) |\n */\nexport const PluginGeomUpdateProfileScaleArgs = z.object({\n profile: ProfileHandle,\n factor: z.union([z.number(), Vec3Components]),\n pivot: Vec3Handle.optional(),\n})\n\nexport type PluginGeomUpdateProfileScaleArgs = z.infer<typeof PluginGeomUpdateProfileScaleArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateProfileApi.mirror}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to mirror |\n * | `plane` | `{ point: `{@linkcode Vec3Handle}`, normal: `{@linkcode Vec3Handle}` }` | Mirror plane defined by a point on it and its normal |\n */\nexport const PluginGeomUpdateProfileMirrorArgs = z.object({\n profile: ProfileHandle,\n plane: z.object({\n point: Vec3Handle,\n normal: Vec3Handle,\n }),\n})\n\nexport type PluginGeomUpdateProfileMirrorArgs = z.infer<typeof PluginGeomUpdateProfileMirrorArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateProfileApi.add}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to append to |\n * | `curve` | {@linkcode CurveHandle} | The curve to append; it must connect to the chosen end |\n * | `position` | `\"start\"` \\| `\"end\"` | Optional end to append at (defaults to `\"end\"`) |\n */\nexport const PluginGeomUpdateProfileAddArgs = z.object({\n profile: ProfileHandle,\n curve: CurveHandle,\n position: z.enum([\"start\", \"end\"]).optional(),\n})\n\nexport type PluginGeomUpdateProfileAddArgs = z.infer<typeof PluginGeomUpdateProfileAddArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateProfileApi.remove}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to remove a curve from |\n * | `position` | `\"start\"` \\| `\"end\"` | Optional end to remove from (defaults to `\"end\"`) |\n */\nexport const PluginGeomUpdateProfileRemoveArgs = z.object({\n profile: ProfileHandle,\n position: z.enum([\"start\", \"end\"]).optional(),\n})\n\nexport type PluginGeomUpdateProfileRemoveArgs = z.infer<typeof PluginGeomUpdateProfileRemoveArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateProfileApi.reverse}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to reverse |\n */\nexport const PluginGeomUpdateProfileReverseArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomUpdateProfileReverseArgs = z.infer<typeof PluginGeomUpdateProfileReverseArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateProfileApi.simplify}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The profile to simplify |\n */\nexport const PluginGeomUpdateProfileSimplifyArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomUpdateProfileSimplifyArgs = z.infer<typeof PluginGeomUpdateProfileSimplifyArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport {\n ContourHandle,\n ProfileHandle,\n Vec3Handle,\n Vec3Components,\n} from \"../../../../handles\"\n\n/**\n * Contour editing — produce NEW contours from an existing one (all-handle model, §11).\n *\n * A contour is an outer {@linkcode ProfileHandle} plus zero or more inner profiles\n * that punch holes in it. Every method here is an immutable derive-new operation:\n * it takes an opaque {@linkcode ContourHandle} (plus any extra inputs) and returns a\n * fresh {@linkcode ContourHandle} for the resulting contour. The input contour is\n * never mutated — the original handle keeps referring to the unchanged contour. Read\n * the resulting geometry back as plain values with the query namespace.\n *\n * Accessed via `snaptrude.core.geom.update.contour`.\n */\nexport abstract class PluginGeomUpdateContourApi {\n constructor() {}\n\n /**\n * Offset a contour inward/outward by a signed distance. Immutable — returns a NEW\n * contour and leaves the input unchanged.\n *\n * @param contour The contour to offset\n * @param distance Signed offset distance (outward when positive, inward when negative)\n * @returns The offset contour as a NEW {@linkcode ContourHandle}\n *\n * @examplePrompt Offset this boundary 500mm inward\n * @examplePrompt Shrink this floor outline by half a metre all around\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(10, 8)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const inset = await snaptrude.core.geom.update.contour.offset(contour, -0.5)\n * const area = await snaptrude.core.geom.query.contour.getArea(inset)\n * ```\n */\n public abstract offset(\n contour: ContourHandle,\n distance: number,\n ): PluginApiReturn<ContourHandle>\n\n /**\n * Translate a contour by a vector. Immutable — returns a NEW contour and leaves\n * the input unchanged.\n *\n * @param contour The contour to move\n * @param translation Translation vector to move the contour by\n * @returns The moved contour as a NEW {@linkcode ContourHandle}\n *\n * @examplePrompt Move this shape 2 metres to the right\n * @examplePrompt Shift this outline over by 5 feet\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(6, 4)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const shift = await snaptrude.core.math.vec3.new(2, 0, 0)\n * const moved = await snaptrude.core.geom.update.contour.move(contour, shift)\n * ```\n */\n public abstract move(\n contour: ContourHandle,\n translation: Vec3Handle,\n ): PluginApiReturn<ContourHandle>\n\n /**\n * Rotate a contour about an axis through an optional pivot. Immutable — returns a\n * NEW contour and leaves the input unchanged.\n *\n * @param contour The contour to rotate\n * @param axis Rotation axis direction\n * @param angle Rotation angle in radians\n * @param pivot Optional pivot point to rotate about (defaults to the origin)\n * @returns The rotated contour as a NEW {@linkcode ContourHandle}\n *\n * @examplePrompt Rotate this shape 45 degrees\n * @examplePrompt Turn this outline 90 degrees about its corner\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(6, 4)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const axis = await snaptrude.core.math.vec3.new(0, 1, 0)\n * const pivot = await snaptrude.core.math.vec3.new(3, 0, 2)\n * const rotated = await snaptrude.core.geom.update.contour.rotate(contour, axis, Math.PI / 4, pivot)\n * ```\n */\n public abstract rotate(\n contour: ContourHandle,\n axis: Vec3Handle,\n angle: number,\n pivot?: Vec3Handle,\n ): PluginApiReturn<ContourHandle>\n\n /**\n * Scale a contour uniformly or per-axis about an optional pivot. Immutable —\n * returns a NEW contour and leaves the input unchanged.\n *\n * @param contour The contour to scale\n * @param factor Uniform scale factor, or per-axis factors\n * @param pivot Optional pivot point to scale about (defaults to the origin)\n * @returns The scaled contour as a NEW {@linkcode ContourHandle}\n *\n * @examplePrompt Scale this shape up by a factor of 2\n * @examplePrompt Make this outline half its current size\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(6, 4)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const doubled = await snaptrude.core.geom.update.contour.scale(contour, 2)\n * const stretched = await snaptrude.core.geom.update.contour.scale(contour, { x: 2, y: 1, z: 1 })\n * ```\n */\n public abstract scale(\n contour: ContourHandle,\n factor: number | Vec3Components,\n pivot?: Vec3Handle,\n ): PluginApiReturn<ContourHandle>\n\n /**\n * Mirror a contour across a plane. Immutable — returns a NEW contour and leaves\n * the input unchanged.\n *\n * @param contour The contour to mirror\n * @param plane Mirror plane defined by a point on it and its normal\n * @returns The mirrored contour as a NEW {@linkcode ContourHandle}\n *\n * @examplePrompt Mirror this shape across the gridline\n * @examplePrompt Flip this outline to its mirror image\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(6, 4)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const point = await snaptrude.core.math.vec3.new(0, 0, 0)\n * const normal = await snaptrude.core.math.vec3.new(1, 0, 0)\n * const mirrored = await snaptrude.core.geom.update.contour.mirror(contour, { point, normal })\n * ```\n */\n public abstract mirror(\n contour: ContourHandle,\n plane: { point: Vec3Handle; normal: Vec3Handle },\n ): PluginApiReturn<ContourHandle>\n\n /**\n * Add a hole to a contour by appending an inner profile. Immutable — returns a NEW\n * contour and leaves the input unchanged.\n *\n * @param contour The contour to add a hole to\n * @param hole The inner profile to add as a hole\n * @returns The contour with the added hole as a NEW {@linkcode ContourHandle}\n *\n * @examplePrompt Cut a hole in this shape\n * @examplePrompt Punch an opening through this floor outline\n *\n * # Example\n * ```ts\n * const outer = await snaptrude.core.geom.create.profileRect(10, 8)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(outer)\n * const hole = await snaptrude.core.geom.create.profileRect(2, 2)\n * const withHole = await snaptrude.core.geom.update.contour.addHole(contour, hole)\n * const count = await snaptrude.core.geom.query.contour.getHoleCount(withHole) // 1\n * ```\n */\n public abstract addHole(\n contour: ContourHandle,\n hole: ProfileHandle,\n ): PluginApiReturn<ContourHandle>\n\n /**\n * Remove a hole from a contour by inner-profile index. Immutable — returns a NEW\n * contour and leaves the input unchanged.\n *\n * @param contour The contour to remove a hole from\n * @param index Zero-based index of the inner profile (hole) to remove\n * @returns The contour with the hole removed as a NEW {@linkcode ContourHandle}\n *\n * @examplePrompt Remove the hole from this shape\n * @examplePrompt Fill in the opening in this floor outline\n *\n * # Example\n * ```ts\n * const outer = await snaptrude.core.geom.create.profileRect(10, 8)\n * const hole = await snaptrude.core.geom.create.profileRect(2, 2)\n * const contour = await snaptrude.core.geom.create.contourFromProfiles(outer, [hole])\n * const solid = await snaptrude.core.geom.update.contour.removeHole(contour, 0)\n * ```\n */\n public abstract removeHole(\n contour: ContourHandle,\n index: number,\n ): PluginApiReturn<ContourHandle>\n}\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateContourApi.offset}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to offset |\n * | `distance` | `number` | Signed offset distance (outward when positive, inward when negative) |\n */\nexport const PluginGeomUpdateContourOffsetArgs = z.object({\n contour: ContourHandle,\n distance: z.number(),\n})\n\nexport type PluginGeomUpdateContourOffsetArgs = z.infer<typeof PluginGeomUpdateContourOffsetArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateContourApi.move}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to move |\n * | `translation` | {@linkcode Vec3Handle} | Translation vector to move the contour by |\n */\nexport const PluginGeomUpdateContourMoveArgs = z.object({\n contour: ContourHandle,\n translation: Vec3Handle,\n})\n\nexport type PluginGeomUpdateContourMoveArgs = z.infer<typeof PluginGeomUpdateContourMoveArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateContourApi.rotate}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to rotate |\n * | `axis` | {@linkcode Vec3Handle} | Rotation axis direction |\n * | `angle` | `number` | Rotation angle in radians |\n * | `pivot` | {@linkcode Vec3Handle} | Optional pivot point to rotate about (defaults to the origin) |\n */\nexport const PluginGeomUpdateContourRotateArgs = z.object({\n contour: ContourHandle,\n axis: Vec3Handle,\n angle: z.number(),\n pivot: Vec3Handle.optional(),\n})\n\nexport type PluginGeomUpdateContourRotateArgs = z.infer<typeof PluginGeomUpdateContourRotateArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateContourApi.scale}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to scale |\n * | `factor` | `number` \\| {@linkcode Vec3Components} | Uniform scale factor, or per-axis factors |\n * | `pivot` | {@linkcode Vec3Handle} | Optional pivot point to scale about (defaults to the origin) |\n */\nexport const PluginGeomUpdateContourScaleArgs = z.object({\n contour: ContourHandle,\n factor: z.union([z.number(), Vec3Components]),\n pivot: Vec3Handle.optional(),\n})\n\nexport type PluginGeomUpdateContourScaleArgs = z.infer<typeof PluginGeomUpdateContourScaleArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateContourApi.mirror}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to mirror |\n * | `plane` | `{ point: `{@linkcode Vec3Handle}`, normal: `{@linkcode Vec3Handle}` }` | Mirror plane defined by a point on it and its normal |\n */\nexport const PluginGeomUpdateContourMirrorArgs = z.object({\n contour: ContourHandle,\n plane: z.object({\n point: Vec3Handle,\n normal: Vec3Handle,\n }),\n})\n\nexport type PluginGeomUpdateContourMirrorArgs = z.infer<typeof PluginGeomUpdateContourMirrorArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateContourApi.addHole}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to add a hole to |\n * | `hole` | {@linkcode ProfileHandle} | The inner profile to add as a hole |\n */\nexport const PluginGeomUpdateContourAddHoleArgs = z.object({\n contour: ContourHandle,\n hole: ProfileHandle,\n})\n\nexport type PluginGeomUpdateContourAddHoleArgs = z.infer<typeof PluginGeomUpdateContourAddHoleArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomUpdateContourApi.removeHole}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The contour to remove a hole from |\n * | `index` | `number` | Zero-based index of the inner profile (hole) to remove |\n */\nexport const PluginGeomUpdateContourRemoveHoleArgs = z.object({\n contour: ContourHandle,\n index: z.number(),\n})\n\nexport type PluginGeomUpdateContourRemoveHoleArgs = z.infer<typeof PluginGeomUpdateContourRemoveHoleArgs>\n","import { PluginGeomUpdateCurveApi } from \"./curve\"\nimport { PluginGeomUpdateProfileApi } from \"./profile\"\nimport { PluginGeomUpdateContourApi } from \"./contour\"\n\n/**\n * Curve/profile/contour update namespace — derive NEW geometry by editing existing\n * handles (all-handle model, §11). Inputs are never mutated; every method returns a\n * fresh handle.\n *\n * - {@linkcode PluginGeomUpdateApi.curve} — extend, split, trim, offset, reverse\n * - {@linkcode PluginGeomUpdateApi.profile} — offset, affine, add/remove/reverse/simplify\n * - {@linkcode PluginGeomUpdateApi.contour} — offset, affine, addHole/removeHole\n *\n * Accessed via `snaptrude.core.geom.update`.\n */\nexport abstract class PluginGeomUpdateApi {\n /** Curve editing operations. See {@linkcode PluginGeomUpdateCurveApi}. */\n public abstract curve: PluginGeomUpdateCurveApi\n /** Profile editing operations. See {@linkcode PluginGeomUpdateProfileApi}. */\n public abstract profile: PluginGeomUpdateProfileApi\n /** Contour editing operations. See {@linkcode PluginGeomUpdateContourApi}. */\n public abstract contour: PluginGeomUpdateContourApi\n\n constructor() {}\n}\n\nexport * from \"./curve\"\nexport * from \"./profile\"\nexport * from \"./contour\"\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport { ProfileHandle, ContourHandle } from \"../../../../handles\"\n\n/**\n * Geometry deletion — release transient geometry resource handles (all-handle model, §11).\n *\n * Methods here free a handle's backing registry entry and reclaim its share of the\n * plugin's resource quota. This is purely a handle-lifecycle operation: it does NOT\n * tear down or delete any engine-side geometry. Once released, the handle is no\n * longer resolvable and must not be reused.\n *\n * Accessed via `snaptrude.core.geom.delete`.\n */\nexport abstract class PluginGeomDeleteApi {\n constructor() {}\n\n /**\n * Free a transient profile resource handle — releases its registry entry and\n * reclaims its share of the plugin's resource quota. This is a handle-lifecycle\n * operation only and does NOT tear down any engine-side geometry.\n *\n * @param profile The transient profile handle to release\n * @returns Nothing\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const area = await snaptrude.core.geom.query.profile.getArea(rect)\n * await snaptrude.core.geom.delete.profile(rect) // rect is no longer resolvable\n * ```\n */\n public abstract profile(profile: ProfileHandle): PluginApiReturn<void>\n\n /**\n * Free a transient contour resource handle — releases its registry entry and\n * reclaims its share of the plugin's resource quota. Handle-lifecycle only; does\n * NOT tear down engine-side geometry, nor the contour's child profile handles.\n *\n * @param contour The transient contour handle to release\n * @returns Nothing\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const area = await snaptrude.core.geom.query.contour.getArea(contour)\n * await snaptrude.core.geom.delete.contour(contour) // contour freed; rect still valid\n * ```\n */\n public abstract contour(contour: ContourHandle): PluginApiReturn<void>\n}\n\n/**\n * Arguments for {@linkcode PluginGeomDeleteApi.profile}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | The transient profile handle to release |\n */\nexport const PluginGeomDeleteProfileArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginGeomDeleteProfileArgs = z.infer<typeof PluginGeomDeleteProfileArgs>\n\n/**\n * Arguments for {@linkcode PluginGeomDeleteApi.contour}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | The transient contour handle to release |\n */\nexport const PluginGeomDeleteContourArgs = z.object({\n contour: ContourHandle,\n})\n\nexport type PluginGeomDeleteContourArgs = z.infer<typeof PluginGeomDeleteContourArgs>\n","import { PluginGeomCreateApi } from \"./create\"\nimport { PluginGeomQueryApi } from \"./query\"\nimport { PluginGeomUpdateApi } from \"./update\"\nimport { PluginGeomDeleteApi } from \"./delete\"\n\n/**\n * Geometry kernel — domain-free construction, query, editing, and disposal of\n * curves (lines / arcs) and profiles. No BIM/AEC knowledge lives here; build\n * geometry bottom-up: points ({@linkcode Vec3Handle}) → curves → profiles → entities.\n *\n * - {@linkcode PluginGeomApi.create} — construct lines, arcs, and profiles\n * - {@linkcode PluginGeomApi.query} — read curve / arc / profile geometry and relationships\n * - {@linkcode PluginGeomApi.update} — derive new curves / profiles (immutable edits)\n * - {@linkcode PluginGeomApi.delete} — free a transient profile resource handle\n *\n * Profiles can then be used with entity creation methods like\n * {@linkcode PluginSpaceApi.createFromProfile}.\n */\nexport abstract class PluginGeomApi {\n /** Curve and profile construction. See {@linkcode PluginGeomCreateApi}. */\n public abstract create: PluginGeomCreateApi\n /** Curve, arc, and profile queries. See {@linkcode PluginGeomQueryApi}. */\n public abstract query: PluginGeomQueryApi\n /** Curve and profile editing (derive-new). See {@linkcode PluginGeomUpdateApi}. */\n public abstract update: PluginGeomUpdateApi\n /** Resource-handle disposal (profile). See {@linkcode PluginGeomDeleteApi}. */\n public abstract delete: PluginGeomDeleteApi\n\n constructor() {}\n}\n\nexport * from \"./create\"\nexport * from \"./query\"\nexport * from \"./update\"\nexport * from \"./delete\"\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\n\n/**\n * Undo / redo of committed history entries.\n *\n * History steps operate on Snaptrude's command stack: {@linkcode PluginHistoryApi.undo}\n * steps back over committed entries, {@linkcode PluginHistoryApi.redo} re-applies\n * undone ones. Both take an optional step count (default 1) and report how many\n * steps were actually applied — fewer than requested when the stack runs out.\n *\n * Accessed via `snaptrude.core.history`.\n */\nexport abstract class PluginHistoryApi {\n constructor() {}\n\n /**\n * Step back over committed history entries.\n *\n * @param steps - (Optional) The number of entries to undo (default 1).\n * @returns A {@linkcode PluginHistoryStepResult} with `stepsApplied` — the\n * entries actually undone (≤ `steps`; fewer if the undo stack ran out).\n *\n * @examplePrompt Undo my last change\n * @examplePrompt Undo the last 3 actions\n * @examplePrompt Revert what I just did to the model\n * @examplePrompt Step back one change\n * @examplePrompt Take back that last edit\n *\n * # Example\n * ```ts\n * await snaptrude.core.history.undo() // one step\n * await snaptrude.core.history.undo(3) // up to three steps\n * ```\n */\n public abstract undo(steps?: number): PluginApiReturn<PluginHistoryStepResult>\n\n /**\n * Step forward over previously undone entries. Symmetric with\n * {@linkcode PluginHistoryApi.undo}.\n *\n * @param steps - (Optional) The number of entries to redo (default 1).\n * @returns A {@linkcode PluginHistoryStepResult} with `stepsApplied` — the\n * entries actually redone (≤ `steps`; fewer if the redo stack ran out).\n *\n * @examplePrompt Redo the change I just undid\n * @examplePrompt Redo the last two undone actions\n * @examplePrompt Bring back the edit I reverted\n * @examplePrompt Step forward again in the history\n *\n * # Example\n * ```ts\n * await snaptrude.core.history.redo()\n * await snaptrude.core.history.redo(2)\n * ```\n */\n public abstract redo(steps?: number): PluginApiReturn<PluginHistoryStepResult>\n}\n\n/**\n * Arguments for {@linkcode PluginHistoryApi.undo} / {@linkcode PluginHistoryApi.redo}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `steps` | `number?` | Number of history entries to step (positive integer). Defaults to 1. |\n */\nexport const PluginHistoryStepArgs = z.object({\n steps: z.number().int().positive().optional(),\n})\n\nexport type PluginHistoryStepArgs = z.infer<typeof PluginHistoryStepArgs>\n\n/**\n * Result of {@linkcode PluginHistoryApi.undo} / {@linkcode PluginHistoryApi.redo}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `stepsApplied` | `number` | History entries actually stepped — `≤ steps`, fewer when the stack ran out. |\n */\nexport const PluginHistoryStepResult = z.object({\n stepsApplied: z.number().int().nonnegative(),\n})\n\nexport type PluginHistoryStepResult = z.infer<typeof PluginHistoryStepResult>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\n\n/**\n * Unit-type queries and conversion.\n *\n * Snaptrude stores all geometry in an internal `babylon` unit. These methods\n * read the available unit types, the internal (`babylon`) type, and the current\n * project type; set the current project type; and convert values between any two\n * unit types.\n *\n * Accessed via `snaptrude.core.units`.\n */\nexport abstract class PluginUnitsApi {\n constructor() {}\n\n /**\n * List the selectable real-world unit types (excludes the internal `babylon`\n * storage type, which is read via {@linkcode PluginUnitsApi.getBabylonType}).\n *\n * @examplePrompt What units can I use in this project?\n * @examplePrompt List all the available measurement units\n * @examplePrompt Which unit systems does Snaptrude support?\n * @examplePrompt Show the unit options I could switch the model to\n *\n * # Example\n * ```ts\n * const types = await snaptrude.core.units.listTypes()\n * console.log(types) // [\"meters\", \"feet-inches\", \"inches\", ...]\n * ```\n */\n public abstract listTypes(): PluginApiReturn<PUnitType[]>\n\n /**\n * Get the internal storage unit type that all geometry is kept in — always\n * `\"babylon\"` — for use as one side of a {@linkcode PluginUnitsApi.convert} call.\n *\n * @examplePrompt What unit does Snaptrude store geometry in internally?\n * @examplePrompt Get the internal babylon unit type\n * @examplePrompt Which unit are raw model coordinates saved in?\n *\n * # Example\n * ```ts\n * const babylon = await snaptrude.core.units.getBabylonType() // \"babylon\"\n * const meters = await snaptrude.core.units.convert(10, babylon, \"meters\")\n * ```\n */\n public abstract getBabylonType(): PluginApiReturn<PUnitType>\n\n /**\n * Get the current project's unit type — the unit lengths are displayed and\n * entered in. Paired with {@linkcode PluginUnitsApi.setType}.\n *\n * @examplePrompt What units is this project using?\n * @examplePrompt Are we working in metric or imperial?\n * @examplePrompt Check the current measurement unit of the model\n * @examplePrompt Is the file set to millimetres or feet and inches?\n *\n * # Example\n * ```ts\n * const type = await snaptrude.core.units.getType()\n * console.log(type) // e.g. \"millimeters\"\n * ```\n */\n public abstract getType(): PluginApiReturn<PUnitType>\n\n /**\n * Set the current project's unit type. Paired with {@linkcode PluginUnitsApi.getType}.\n *\n * @param type - The unit type to set as the project unit.\n * @returns `true` if applied; `false` if `type` is not a settable project unit\n * (e.g. `kilometers`, `miles`, `babylon`).\n *\n * @examplePrompt Change the project units to millimeters\n * @examplePrompt Switch this model to feet and inches\n * @examplePrompt Set the working units to metric\n * @examplePrompt Make the drawing use centimetres instead of meters\n *\n * # Example\n * ```ts\n * await snaptrude.core.units.setType(\"meters\")\n * ```\n */\n public abstract setType(type: PUnitType): PluginApiReturn<boolean>\n\n /**\n * Convert a value between two unit types.\n *\n * @param value - The numeric value to convert.\n * @param from - Source unit type.\n * @param to - Target unit type.\n * @param degree - (Optional) 1 = length, 2 = area, 3 = volume. Defaults to 1.\n * @returns The converted numeric value.\n *\n * @examplePrompt Convert 5 meters to feet and inches\n * @examplePrompt How many millimetres is 12 feet?\n * @examplePrompt Change this area from internal units to square metres\n * @examplePrompt Turn 2500 mm into meters\n * @examplePrompt Convert a volume value from babylon units to cubic feet\n *\n * # Example\n * ```ts\n * // 5 meters → internal babylon units\n * const b = await snaptrude.core.units.convert(5, \"meters\", \"babylon\")\n * // an internal area → square metres\n * const m2 = await snaptrude.core.units.convert(area, \"babylon\", \"meters\", 2)\n * ```\n */\n public abstract convert(\n value: number,\n from: PUnitType,\n to: PUnitType,\n degree?: number,\n ): PluginApiReturn<number>\n}\n\n/**\n * Supported unit types. `babylon` is Snaptrude's internal storage unit; the rest\n * are real-world units. Mirrors the engine `Converter.UNITS` vocabulary.\n */\nexport const PUnitType = z.enum([\n \"meters\",\n \"feet-inches\",\n \"inches\",\n \"centimeters\",\n \"millimeters\",\n \"kilometers\",\n \"miles\",\n \"babylon\",\n])\n\nexport type PUnitType = z.infer<typeof PUnitType>\n\n/**\n * Arguments for {@linkcode PluginUnitsApi.setType}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `type` | {@linkcode PUnitType} | The unit type to set as the project unit |\n */\nexport const PluginUnitsSetTypeArgs = z.object({\n type: PUnitType,\n})\n\nexport type PluginUnitsSetTypeArgs = z.infer<typeof PluginUnitsSetTypeArgs>\n\n/**\n * Arguments for {@linkcode PluginUnitsApi.convert}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `value` | `number` | The numeric value to convert |\n * | `from` | {@linkcode PUnitType} | Source unit type |\n * | `to` | {@linkcode PUnitType} | Target unit type |\n * | `degree` | `1 \\| 2 \\| 3` | (Optional) 1 = length, 2 = area, 3 = volume. Defaults to 1 |\n */\nexport const PluginUnitsConvertArgs = z.object({\n value: z.number(),\n from: PUnitType,\n to: PUnitType,\n degree: z.number().int().min(1).max(3).optional(),\n})\n\nexport type PluginUnitsConvertArgs = z.infer<typeof PluginUnitsConvertArgs>\n","import { PluginApiReturn } from \"../../../types\"\n\n/**\n * Camera zoom controls.\n *\n * Frame the viewport camera onto scene geometry — mirrors the canvas zoom menu\n * (\"Zoom extents\" / \"Zoom to selection\"). Accessed via `snaptrude.core.zoom`.\n */\nexport abstract class PluginZoomApi {\n constructor() {}\n\n /**\n * Zoom (fit) the camera to all geometry in the scene — the \"zoom extents\" action.\n *\n * @returns `true` once the camera has been framed to the scene.\n *\n * @examplePrompt Zoom out so I can see the whole model\n * @examplePrompt Fit everything in the view\n * @examplePrompt Frame the entire building in the viewport\n * @examplePrompt Do a zoom extents on the canvas\n * @examplePrompt Show me the full scene\n *\n * # Example\n * ```ts\n * await snaptrude.core.zoom.extents()\n * ```\n */\n public abstract extents(): PluginApiReturn<boolean>\n\n /**\n * Zoom (fit) the camera to the current selection.\n *\n * @returns `true` if there was a selection to frame; `false` if nothing is\n * selected (no-op).\n *\n * @examplePrompt Zoom in on what I have selected\n * @examplePrompt Frame the selected walls in the view\n * @examplePrompt Focus the camera on my current selection\n * @examplePrompt Fit the view to the selected room\n *\n * # Example\n * ```ts\n * await snaptrude.core.zoom.selection()\n * ```\n */\n public abstract selection(): PluginApiReturn<boolean>\n}\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\n\n/**\n * Project-level settings and info.\n *\n * Accessed via `snaptrude.core.project`. Currently exposes\n * {@linkcode PluginProjectApi.settings} (snap + grid controls).\n */\nexport abstract class PluginProjectApi {\n constructor() {}\n\n /** Project settings — snaps and grid. See {@linkcode PluginProjectSettingsApi}. */\n public abstract settings: PluginProjectSettingsApi\n}\n\n/**\n * Project settings — tolerance, snaps, and grid.\n *\n * Accessed via `snaptrude.core.project.settings`.\n */\nexport abstract class PluginProjectSettingsApi {\n constructor() {}\n\n /**\n * Get the project tolerance as a numeric magnitude.\n *\n * The engine stores tolerance as a discrete per-unit precision option; this\n * returns its magnitude (decimal precision `\"0.00\"` → `0.01`; fraction `\"1/4\"`\n * → `0.25`).\n *\n * @examplePrompt What is the tolerance setting in this project?\n * @examplePrompt Check the current dimension precision of the model\n * @examplePrompt How precise are the measurements in this project?\n * @examplePrompt Show me the project's tolerance value\n *\n * # Example\n * ```ts\n * const tolerance = await snaptrude.core.project.settings.getTolerance()\n * console.log(tolerance) // e.g. 0.01\n * ```\n */\n public abstract getTolerance(): PluginApiReturn<number>\n\n /**\n * Set the project tolerance. The value snaps to the **nearest allowed**\n * per-unit precision option (tolerance is a discrete dropdown, not arbitrary).\n *\n * @param value - Target tolerance magnitude; snaps to the nearest allowed option.\n * @returns `true` once applied; `false` if no tolerance options are available.\n *\n * @examplePrompt Set the project tolerance to 0.01\n * @examplePrompt Change the dimension precision to two decimal places\n * @examplePrompt Round dimensions to the nearest quarter inch\n * @examplePrompt Make the measurements in this project more precise\n *\n * # Example\n * ```ts\n * // snaps to the nearest allowed precision option\n * const applied = await snaptrude.core.project.settings.setTolerance(0.01)\n * if (!applied) console.log(\"no tolerance options available\")\n * ```\n */\n public abstract setTolerance(value: number): PluginApiReturn<boolean>\n\n /** Snap controls (dimension / angle / parallel / normal / magnetic). See {@linkcode PluginSnapsApi}. */\n public abstract snaps: PluginSnapsApi\n /** Grid controls. See {@linkcode PluginGridApi}. */\n public abstract grid: PluginGridApi\n}\n\n/**\n * Snap controls. Dimension and angle snaps each have a numeric threshold plus an\n * on/off toggle; parallel, normal, and magnetic snaps are on/off only.\n * (`normal` is the perpendicular snap.)\n *\n * Accessed via `snaptrude.core.project.settings.snaps`.\n */\nexport abstract class PluginSnapsApi {\n constructor() {}\n\n /**\n * Set the dimension-snap threshold — the length increment that drawing and\n * editing snap to when dimension snapping is on.\n *\n * @param value - The snap threshold distance.\n *\n * @examplePrompt Set the dimension snap to 100mm\n * @examplePrompt Change the snap distance to half a metre\n * @examplePrompt Make the cursor snap every 6 inches when drawing\n * @examplePrompt Adjust the snapping increment for lengths\n *\n * # Example\n * ```ts\n * // the threshold only applies while dimension snapping is on\n * await snaptrude.core.project.settings.snaps.setDimension(100)\n * await snaptrude.core.project.settings.snaps.enableDimension()\n * ```\n */\n public abstract setDimension(value: number): PluginApiReturn<boolean>\n /**\n * Get the current dimension-snap threshold — the length increment that\n * drawing and editing snap to when dimension snapping is on.\n *\n * @examplePrompt What is the dimension snap distance?\n * @examplePrompt Check the current snap increment for drawing\n * @examplePrompt How far apart are the length snaps set?\n * @examplePrompt Show me the snap spacing value\n *\n * # Example\n * ```ts\n * const increment = await snaptrude.core.project.settings.snaps.getDimension()\n * console.log(increment)\n * ```\n */\n public abstract getDimension(): PluginApiReturn<number>\n /**\n * Turn dimension snapping on, so drawing and editing snap to the configured\n * length increment.\n *\n * @examplePrompt Turn on dimension snapping\n * @examplePrompt Enable snapping to set lengths while I draw\n * @examplePrompt Make my walls snap to round dimensions\n * @examplePrompt Switch length snapping back on\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.snaps.enableDimension()\n * ```\n */\n public abstract enableDimension(): PluginApiReturn<boolean>\n /**\n * Turn dimension snapping off, so lengths no longer snap to the configured\n * increment while drawing.\n *\n * @examplePrompt Turn off dimension snapping\n * @examplePrompt Stop snapping to fixed lengths when I draw\n * @examplePrompt Disable the length snap so I can draw freely\n * @examplePrompt I don't want dimensions to snap anymore\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.snaps.disableDimension()\n * ```\n */\n public abstract disableDimension(): PluginApiReturn<boolean>\n\n /**\n * Set the angle-snap threshold in degrees — the angular increment that\n * drawing snaps to when angle snapping is on.\n *\n * @param value - The snap threshold in degrees.\n *\n * @examplePrompt Set the angle snap to 15 degrees\n * @examplePrompt Change angle snapping to every 45 degrees\n * @examplePrompt Make drawing snap at 30 degree increments\n * @examplePrompt Adjust the rotation snap angle\n *\n * # Example\n * ```ts\n * // snap drawing to 15-degree increments (applies while angle snapping is on)\n * await snaptrude.core.project.settings.snaps.setAngle(15)\n * await snaptrude.core.project.settings.snaps.enableAngle()\n * ```\n */\n public abstract setAngle(value: number): PluginApiReturn<boolean>\n /**\n * Get the current angle-snap threshold in degrees — the angular increment\n * that drawing snaps to when angle snapping is on.\n *\n * @examplePrompt What angle does drawing snap to?\n * @examplePrompt Check the current angle snap in degrees\n * @examplePrompt Show me the angle snapping increment\n * @examplePrompt How many degrees is the angle snap set to?\n *\n * # Example\n * ```ts\n * const degrees = await snaptrude.core.project.settings.snaps.getAngle()\n * console.log(degrees)\n * ```\n */\n public abstract getAngle(): PluginApiReturn<number>\n /**\n * Turn angle snapping on, so drawn lines snap to the configured angle\n * increment.\n *\n * @examplePrompt Turn on angle snapping\n * @examplePrompt Enable snapping to angles while drawing\n * @examplePrompt Make my lines snap to set angles\n * @examplePrompt Switch angle snap back on\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.snaps.enableAngle()\n * ```\n */\n public abstract enableAngle(): PluginApiReturn<boolean>\n /**\n * Turn angle snapping off, so lines can be drawn at any angle without\n * snapping to fixed increments.\n *\n * @examplePrompt Turn off angle snapping\n * @examplePrompt Stop lines snapping to fixed angles\n * @examplePrompt Disable the angle snap so I can draw at any angle\n * @examplePrompt Remove angle snapping while sketching\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.snaps.disableAngle()\n * ```\n */\n public abstract disableAngle(): PluginApiReturn<boolean>\n\n /**\n * Turn parallel snapping on, so drawing snaps when the cursor lines up\n * parallel to existing edges.\n *\n * @examplePrompt Turn on parallel snapping\n * @examplePrompt Enable snapping to parallel lines\n * @examplePrompt Help me draw walls parallel to existing ones\n * @examplePrompt Snap to parallel edges when drawing\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.snaps.enableParallel()\n * ```\n */\n public abstract enableParallel(): PluginApiReturn<boolean>\n /**\n * Turn parallel snapping off, so drawing no longer snaps to directions\n * parallel to existing edges.\n *\n * @examplePrompt Turn off parallel snapping\n * @examplePrompt Stop snapping to parallel edges\n * @examplePrompt Disable the parallel snap guide\n * @examplePrompt I don't want my lines snapping parallel anymore\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.snaps.disableParallel()\n * ```\n */\n public abstract disableParallel(): PluginApiReturn<boolean>\n\n /**\n * Turn normal (perpendicular) snapping on, so drawing snaps when the cursor\n * is at a right angle to existing edges.\n *\n * @examplePrompt Turn on perpendicular snapping\n * @examplePrompt Enable the normal snap so lines snap at right angles\n * @examplePrompt Snap to perpendicular when I draw walls\n * @examplePrompt Help me draw at 90 degrees to existing edges\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.snaps.enableNormal()\n * ```\n */\n public abstract enableNormal(): PluginApiReturn<boolean>\n /**\n * Turn normal (perpendicular) snapping off, so drawing no longer snaps at\n * right angles to existing edges.\n *\n * @examplePrompt Turn off perpendicular snapping\n * @examplePrompt Disable the normal snap\n * @examplePrompt Stop snapping at right angles to edges\n * @examplePrompt Remove the 90 degree snap guide\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.snaps.disableNormal()\n * ```\n */\n public abstract disableNormal(): PluginApiReturn<boolean>\n\n /**\n * Turn magnetic snapping on, so the cursor is pulled to nearby geometry\n * while drawing.\n *\n * @examplePrompt Turn on magnetic snapping\n * @examplePrompt Enable the magnet snap\n * @examplePrompt Make the cursor stick to nearby geometry when drawing\n * @examplePrompt Switch magnetic snap back on\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.snaps.enableMagnetic()\n * ```\n */\n public abstract enableMagnetic(): PluginApiReturn<boolean>\n /**\n * Turn magnetic snapping off, so the cursor is no longer pulled to nearby\n * geometry while drawing.\n *\n * @examplePrompt Turn off magnetic snapping\n * @examplePrompt Disable the magnet snap\n * @examplePrompt Stop the cursor sticking to nearby objects\n * @examplePrompt The magnetic snap is annoying, switch it off\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.snaps.disableMagnetic()\n * ```\n */\n public abstract disableMagnetic(): PluginApiReturn<boolean>\n}\n\n/**\n * Grid controls — the visual snap-to grid.\n *\n * Accessed via `snaptrude.core.project.settings.grid`.\n */\nexport abstract class PluginGridApi {\n constructor() {}\n\n /**\n * Turn the grid on, showing the visual snap-to grid in the canvas.\n *\n * @examplePrompt Turn on the grid\n * @examplePrompt Show the grid in my project\n * @examplePrompt Enable the drawing grid\n * @examplePrompt Switch the snap grid back on\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.grid.enable()\n * ```\n */\n public abstract enable(): PluginApiReturn<boolean>\n /**\n * Turn the grid off, hiding the visual snap-to grid in the canvas.\n *\n * @examplePrompt Turn off the grid\n * @examplePrompt Hide the grid\n * @examplePrompt Disable the background grid in the canvas\n * @examplePrompt Remove the drawing grid from view\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.grid.disable()\n * ```\n */\n public abstract disable(): PluginApiReturn<boolean>\n /**\n * Set the grid cell value — the size of each cell in the visual snap-to\n * grid.\n *\n * @param value - The grid cell value.\n *\n * @examplePrompt Set the grid spacing to 1 metre\n * @examplePrompt Change the grid cell size to 500mm\n * @examplePrompt Make the grid squares 2 feet wide\n * @examplePrompt Adjust the grid size in this project\n *\n * # Example\n * ```ts\n * await snaptrude.core.project.settings.grid.setValue(1)\n * await snaptrude.core.project.settings.grid.enable()\n * ```\n */\n public abstract setValue(value: number): PluginApiReturn<boolean>\n /**\n * Get the current grid cell value — the size of each cell in the visual\n * snap-to grid.\n *\n * @examplePrompt What is the grid spacing?\n * @examplePrompt Check the current grid cell size\n * @examplePrompt How big are the grid squares?\n * @examplePrompt Show me the grid size setting\n *\n * # Example\n * ```ts\n * const cellSize = await snaptrude.core.project.settings.grid.getValue()\n * console.log(cellSize)\n * ```\n */\n public abstract getValue(): PluginApiReturn<number>\n}\n\n/**\n * Arguments for the snap-threshold setters\n * ({@linkcode PluginSnapsApi.setDimension} / {@linkcode PluginSnapsApi.setAngle}).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `value` | `number` | The snap threshold (distance, or degrees for angle) |\n */\nexport const PluginSnapValueArgs = z.object({\n value: z.number(),\n})\n\nexport type PluginSnapValueArgs = z.infer<typeof PluginSnapValueArgs>\n\n/**\n * Arguments for {@linkcode PluginGridApi.setValue}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `value` | `number` | The grid cell value |\n */\nexport const PluginGridValueArgs = z.object({\n value: z.number(),\n})\n\nexport type PluginGridValueArgs = z.infer<typeof PluginGridValueArgs>\n\n/**\n * Arguments for {@linkcode PluginProjectSettingsApi.setTolerance}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `value` | `number` | Target tolerance magnitude; snaps to the nearest allowed option |\n */\nexport const PluginToleranceArgs = z.object({\n value: z.number(),\n})\n\nexport type PluginToleranceArgs = z.infer<typeof PluginToleranceArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { Vec3Handle, ComponentHandle } from \"../../../handles\"\n\n/**\n * Comments — create, edit, resolve, tag, and list scene/project comments.\n *\n * A comment is an opaque {@link CommentHandle} (its server id). Comments may be\n * anchored to a component at a 3D point, carry @mentions (by email) and emojis,\n * and be resolved / reopened. Accessed via `snaptrude.core.comment`.\n */\nexport abstract class PluginCommentApi {\n constructor() {}\n\n /**\n * Create a comment in the project — optionally pinned to a component at a 3D\n * point — with optional @mentions that notify teammates by email.\n *\n * @param message - Comment text (emojis = plain unicode).\n * @param component - Optional component to anchor the comment to.\n * @param position - Optional pin point; defaults to the component's center.\n * @param mentions - Optional user emails to @mention (appended as real @mention tags).\n * @returns the new {@link CommentHandle}.\n *\n * @examplePrompt Add a comment on this wall saying the height looks wrong\n * @examplePrompt Leave a note on the selected room for the design team\n * @examplePrompt Comment \"verify the door swing\" and tag alex@acme.com\n * @examplePrompt Pin a review note at this point on the slab\n *\n * # Example\n * ```ts\n * const c = await snaptrude.core.comment.create(\n * \"Check this wall 🎉\",\n * spaceId,\n * undefined,\n * [\"alex@acme.com\"],\n * )\n * ```\n */\n public abstract create(\n message: string,\n component?: ComponentHandle,\n position?: Vec3Handle,\n mentions?: string[],\n ): PluginApiReturn<CommentHandle>\n\n /**\n * Edit a comment's message (and optional @mentions).\n *\n * @param comment - The comment to edit.\n * @param message - New message text.\n * @param mentions - Optional user emails to @mention.\n *\n * @examplePrompt Edit my comment to say the beam depth is 600mm\n * @examplePrompt Change the text of this comment\n * @examplePrompt Update the note on the wall and mention priya@studio.com\n * @examplePrompt Reword the comment I just added\n *\n * # Example\n * ```ts\n * const c = await snaptrude.core.comment.create(\"Beam depth TBD\")\n * await snaptrude.core.comment.update(c, \"Beam depth is 600mm\", [\"priya@studio.com\"])\n * ```\n */\n public abstract update(\n comment: CommentHandle,\n message: string,\n mentions?: string[],\n ): PluginApiReturn<boolean>\n\n /**\n * Mark a comment resolved. Paired with {@link PluginCommentApi.reopen}.\n *\n * @param comment - The target comment.\n *\n * @examplePrompt Mark this comment as resolved\n * @examplePrompt Resolve the comment about the staircase\n * @examplePrompt Close out this review note\n * @examplePrompt Set that comment to done\n *\n * # Example\n * ```ts\n * const c = await snaptrude.core.comment.create(\"Verify the door swing\")\n * await snaptrude.core.comment.resolve(c)\n * ```\n */\n public abstract resolve(comment: CommentHandle): PluginApiReturn<boolean>\n\n /**\n * Reopen a resolved comment. Paired with {@link PluginCommentApi.resolve}.\n *\n * @param comment - The target comment.\n *\n * @examplePrompt Reopen this resolved comment\n * @examplePrompt Mark the comment as unresolved again\n * @examplePrompt Bring back the closed note about the window heights\n * @examplePrompt Un-resolve that comment so we can keep discussing it\n *\n * # Example\n * ```ts\n * const [comment] = await snaptrude.core.comment.list()\n * await snaptrude.core.comment.reopen(comment)\n * ```\n */\n public abstract reopen(comment: CommentHandle): PluginApiReturn<boolean>\n\n /**\n * Check whether a comment has been marked resolved.\n *\n * @param comment - The target comment.\n *\n * @examplePrompt Is this comment resolved yet?\n * @examplePrompt Check if the note about the roof has been closed\n * @examplePrompt Has my comment been resolved?\n * @examplePrompt Tell me whether that comment is still open\n *\n * # Example\n * ```ts\n * const [comment] = await snaptrude.core.comment.list()\n * const resolved = await snaptrude.core.comment.isResolved(comment)\n * console.log(resolved ? \"resolved\" : \"still open\")\n * ```\n */\n public abstract isResolved(comment: CommentHandle): PluginApiReturn<boolean>\n\n /**\n * Tag (mention) a user on an existing comment, by email.\n *\n * @param comment - The comment to add a mention to.\n * @param email - The user's email to @mention.\n *\n * @examplePrompt Tag alex@acme.com on this comment\n * @examplePrompt Mention the structural engineer in that note\n * @examplePrompt Add priya@studio.com to the comment about the lobby\n * @examplePrompt Notify a teammate about an existing comment\n *\n * # Example\n * ```ts\n * const [comment] = await snaptrude.core.comment.list()\n * await snaptrude.core.comment.tag(comment, \"alex@acme.com\")\n * ```\n */\n public abstract tag(comment: CommentHandle, email: string): PluginApiReturn<boolean>\n\n /**\n * Permanently remove a comment from the project.\n *\n * @param comment - The target comment.\n *\n * @examplePrompt Delete this comment\n * @examplePrompt Remove the note about the old layout\n * @examplePrompt Get rid of my last comment\n * @examplePrompt Clear that resolved comment off the wall\n *\n * # Example\n * ```ts\n * const [comment] = await snaptrude.core.comment.list()\n * await snaptrude.core.comment.delete(comment)\n * ```\n */\n public abstract delete(comment: CommentHandle): PluginApiReturn<boolean>\n\n /**\n * List every comment in the project (deleted ones are excluded), returned as\n * comment handles you can pass to the other comment methods.\n *\n * @examplePrompt List all the comments in this project\n * @examplePrompt How many comments are on this model?\n * @examplePrompt Show every note in the file\n * @examplePrompt Get all comments so I can check which are resolved\n *\n * # Example\n * ```ts\n * const comments = await snaptrude.core.comment.list()\n * console.log(`${comments.length} comments in the project`)\n * ```\n */\n public abstract list(): PluginApiReturn<CommentHandle[]>\n}\n\n/**\n * Opaque handle to a comment — its server-assigned id (entity-style: a raw,\n * persistable string resolved live, not a registry-minted value handle).\n */\nexport type CommentHandle = string & { readonly __handle: \"comment\" }\nexport const CommentHandle = z\n .string()\n .min(1)\n .transform((s) => s as CommentHandle)\n\n/** `ComponentHandle` is defined in `handles.ts` (imported above) and exported from the\n * package root via `export * from \"./handles\"`. Not re-exported here to avoid an\n * ambiguous double `export *` at the barrel. */\n\n/**\n * Arguments for {@link PluginCommentApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `component` | {@link ComponentHandle}? | Component to anchor the comment to |\n * | `position` | {@link Vec3Handle}? | Pin point; defaults to the component's center |\n * | `message` | `string` | Comment text (emojis = unicode) |\n * | `mentions` | `string[]`? | User emails to @mention |\n */\nexport const PluginCommentCreateArgs = z.object({\n component: ComponentHandle.optional(),\n position: Vec3Handle.optional(),\n message: z.string(),\n mentions: z.array(z.string()).optional(),\n})\n\nexport type PluginCommentCreateArgs = z.infer<typeof PluginCommentCreateArgs>\n\n/**\n * Arguments for {@link PluginCommentApi.update}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `comment` | {@link CommentHandle} | The comment to edit |\n * | `message` | `string` | New message text |\n * | `mentions` | `string[]`? | User emails to @mention |\n */\nexport const PluginCommentUpdateArgs = z.object({\n comment: CommentHandle,\n message: z.string(),\n mentions: z.array(z.string()).optional(),\n})\n\nexport type PluginCommentUpdateArgs = z.infer<typeof PluginCommentUpdateArgs>\n\n/**\n * Arguments for {@link PluginCommentApi.resolve} / {@link PluginCommentApi.reopen}\n * / {@link PluginCommentApi.isResolved} / {@link PluginCommentApi.delete}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `comment` | {@link CommentHandle} | The target comment |\n */\nexport const PluginCommentRefArgs = z.object({\n comment: CommentHandle,\n})\n\nexport type PluginCommentRefArgs = z.infer<typeof PluginCommentRefArgs>\n\n/**\n * Arguments for {@link PluginCommentApi.tag}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `comment` | {@link CommentHandle} | The comment to add a mention to |\n * | `email` | `string` | The user's email to @mention |\n */\nexport const PluginCommentTagArgs = z.object({\n comment: CommentHandle,\n email: z.string(),\n})\n\nexport type PluginCommentTagArgs = z.infer<typeof PluginCommentTagArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\nimport { ComponentHandle, Vec3Components } from \"../../handles\"\n\n/**\n * Groups — read and edit the group hierarchy of the active project.\n *\n * A **group** is a named, lockable container that bundles components (and other\n * groups) so they can be selected and transformed as one. This is the\n * plugin-facing view of that hierarchy: a group's identity, name, member count,\n * lock state, and parent — never the underlying meshes.\n *\n * Reads return plain records and never throw for a missing group (`get` returns\n * `null`, `list` returns `[]`, `isLocked` returns `false`). Ids are stable public\n * strings, never engine mesh handles.\n *\n * Members are moved and copied through the design operations by group id — use\n * {@linkcode PluginDesignApi.transform}`.move` and `design.create.copy`, not a method here.\n * Locking likewise routes through `design.lock`.\n *\n * Sub-namespace members typed as optional (`?`) are **authored ahead of the\n * host** — declared so plugins and codegen can see the shape, but kept out of the\n * discovery manifest until the host lands them (at which point they are promoted\n * to required `abstract` members).\n *\n * Accessed via `snaptrude.core.groups`.\n */\nexport abstract class PluginCoreGroupsApi {\n constructor() {}\n\n /**\n * List every group in the active project.\n *\n * Returns each group's identity, member count, lock state, and parent group\n * (when nested), for the whole project.\n *\n * @returns A {@linkcode PluginCoreGroupsListResult} with a `groups` array\n * (empty when the project has none).\n *\n * @examplePrompt List all the groups in my project\n * @examplePrompt What groups do I have and how many things are in each?\n * @examplePrompt Show every group with its lock state\n * @examplePrompt How many groups are in this model?\n *\n * # Example\n * ```ts\n * const { groups } = await snaptrude.core.groups.list()\n * for (const g of groups) console.log(g.name, g.memberCount, g.isLocked)\n * ```\n */\n public abstract list(): PluginApiReturn<PluginCoreGroupsListResult>\n\n /**\n * Get a single group by id.\n *\n * @param groupId - The id of the group to read.\n * @returns The matching {@linkcode PluginCoreGroupRef}, or `null` if no group\n * has that id.\n *\n * @examplePrompt Get the group with id group-12\n * @examplePrompt Look up a single group by its id\n * @examplePrompt Is group-3 locked and how many members does it have?\n *\n * # Example\n * ```ts\n * const group = await snaptrude.core.groups.get(\"group-12\")\n * if (group) console.log(group.name, group.memberCount)\n * ```\n */\n public abstract get(\n groupId: string,\n ): PluginApiReturn<PluginCoreGroupsGetResult>\n\n /**\n * Get the group a component belongs to.\n *\n * Returns the **innermost** group directly containing the component, or `null`\n * if the component is ungrouped or does not exist.\n *\n * @param componentId - The `Component.id` of the component to look up.\n * @returns The innermost {@linkcode PluginCoreGroupRef} containing the\n * component, or `null`.\n *\n * @examplePrompt Which group is this wall in?\n * @examplePrompt Find the group that contains component cmp_42\n * @examplePrompt Is this element grouped, and if so which group?\n *\n * # Example\n * ```ts\n * const group = await snaptrude.core.groups.getForComponent(\"cmp_42\")\n * console.log(group ? group.name : \"ungrouped\")\n * ```\n */\n public abstract getForComponent(\n componentId: ComponentHandle,\n ): PluginApiReturn<PluginCoreGroupsGetForComponentResult>\n\n /**\n * List the direct members of a group.\n *\n * Returns each direct child as an id + kind (`component` or a nested `group`).\n * Nested groups are returned as members, not flattened.\n *\n * @param groupId - The id of the group whose members to read.\n * @returns A {@linkcode PluginCoreGroupsListMembersResult} with a `members`\n * array (empty when the group is empty or missing).\n *\n * @examplePrompt What's inside group-12?\n * @examplePrompt List the members of this group\n * @examplePrompt Show the components and subgroups in group-3\n *\n * # Example\n * ```ts\n * const { members } = await snaptrude.core.groups.listMembers(\"group-12\")\n * for (const m of members) console.log(m.type, m.id)\n * ```\n */\n public abstract listMembers(\n groupId: string,\n ): PluginApiReturn<PluginCoreGroupsListMembersResult>\n\n /**\n * Report whether a group is locked.\n *\n * A predicate: it never mutates and never throws — an unknown group id returns\n * `false`.\n *\n * @param groupId - The id of the group to test.\n * @returns `true` if the group exists and is locked, otherwise `false`.\n *\n * @examplePrompt Is group-12 locked?\n * @examplePrompt Check whether this group is locked before editing it\n * @examplePrompt Tell me if the group is locked\n *\n * # Example\n * ```ts\n * if (await snaptrude.core.groups.isLocked(\"group-12\")) {\n * console.log(\"locked — unlock it first\")\n * }\n * ```\n */\n public abstract isLocked(\n groupId: string,\n ): PluginApiReturn<PluginCoreGroupsIsLockedResult>\n\n /**\n * Get the axis-aligned bounds of a group.\n *\n * Returns the world-space bounding box of everything in the group — its `min`\n * and `max` corners and the `center` — in internal units, or `null` when the\n * group is empty (has no meshes) or does not exist. `null` is distinct from a\n * real group at the origin, whose box is centered on `{0,0,0}`.\n *\n * @param groupId - The id of the group to measure.\n * @returns A {@linkcode PluginCoreGroupsGetBoundsResult} with `min`, `max`, and\n * `center` points, or `null` if the group is empty or gone.\n *\n * @examplePrompt How big is this group?\n * @examplePrompt Get the bounding box of group-12\n * @examplePrompt Where is the center of this group?\n *\n * # Example\n * ```ts\n * const bounds = await snaptrude.core.groups.getBounds(\"group-12\")\n * if (bounds) console.log(bounds.center.x, bounds.center.y, bounds.center.z)\n * ```\n */\n public abstract getBounds(\n groupId: string,\n ): PluginApiReturn<PluginCoreGroupsGetBoundsResult>\n\n /**\n * Group components into a new group.\n *\n * Bundles the given components under a new group. Pass a `name` to label it;\n * otherwise it gets an auto-generated fallback name that you can change later\n * with {@linkcode PluginCoreGroupsApi.update}.\n *\n * @param componentIds - The ids of the components to group (at least one).\n * @param name - Display name for the new group (auto-generated if omitted).\n * @returns The new group's id (read the full record back with\n * {@linkcode PluginCoreGroupsApi.get}).\n * @throws If a component id is invalid or the group could not be created.\n *\n * @examplePrompt Group the selected components\n * @examplePrompt Make a group called Kitchen from these elements\n * @examplePrompt Bundle components cmp_1 and cmp_2 into a group\n *\n * # Example\n * ```ts\n * const { groupId } = await snaptrude.core.groups.create([\"cmp_1\", \"cmp_2\"], \"Kitchen\")\n * ```\n */\n public abstract create(\n componentIds: ComponentHandle[],\n name?: string,\n ): PluginApiReturn<PluginCoreGroupsCreateResult>\n\n /**\n * Update a group's name and/or membership.\n *\n * A **sparse** update: omitted fields are left unchanged. `addComponentIds`\n * and `removeComponentIds` are applied as membership deltas (add before\n * remove); `name` renames the group.\n *\n * @param groupId - The id of the group to update.\n * @param options - Any of `name`, `addComponentIds`, `removeComponentIds`;\n * omitted fields are left unchanged.\n * @returns The updated {@linkcode PluginCoreGroupRef}.\n * @throws If no group has the given id, or a component id is invalid.\n *\n * @examplePrompt Rename group-12 to Kitchen\n * @examplePrompt Add these two walls to the group\n * @examplePrompt Remove cmp_7 from group-3\n *\n * # Example\n * ```ts\n * const group = await snaptrude.core.groups.update(\"group-12\", {\n * name: \"Kitchen\",\n * addComponentIds: [\"cmp_9\"],\n * })\n * ```\n */\n public abstract update(\n groupId: string,\n options?: {\n name?: string\n addComponentIds?: ComponentHandle[]\n removeComponentIds?: ComponentHandle[]\n },\n ): PluginApiReturn<PluginCoreGroupsUpdateResult>\n\n /**\n * Delete (dissolve) a group.\n *\n * Dissolves the group container. The member elements are **not** deleted —\n * they are returned to the group's parent (or ungrouped at the top level).\n *\n * @param groupId - The id of the group to dissolve.\n * @returns Confirmation that the group was dissolved.\n * @throws If no group has the given id.\n *\n * @examplePrompt Ungroup group-12\n * @examplePrompt Dissolve this group but keep its contents\n * @examplePrompt Delete the group without deleting its members\n *\n * # Example\n * ```ts\n * await snaptrude.core.groups.delete(\"group-12\")\n * ```\n */\n public abstract delete(\n groupId: string,\n ): PluginApiReturn<PluginCoreGroupsDeleteResult>\n}\n\n/**\n * A group in the active project.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Stable public group id (e.g. `\"group-12\"`) — never a mesh handle |\n * | `name` | `string` | Display name (auto-generated fallback until the user sets one) |\n * | `memberCount` | `number` | Number of direct members (components + nested groups) |\n * | `isLocked` | `boolean` | Whether the group is locked against edits |\n * | `parentId` | `string \\| undefined` | Parent group id when this group is nested, else absent |\n */\nexport const PluginCoreGroupRef = z.object({\n id: z.string(),\n name: z.string(),\n memberCount: z.number().int(),\n isLocked: z.boolean(),\n parentId: z.string().optional(),\n})\nexport type PluginCoreGroupRef = z.infer<typeof PluginCoreGroupRef>\n\n/**\n * A direct member of a group.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | `Component.id` for a component member, or the group id for a nested group |\n * | `type` | `\"component\" \\| \"group\"` | Whether this member is a component or a nested group |\n */\nexport const PluginCoreGroupMember = z.object({\n id: z.string(),\n type: z.enum([\"component\", \"group\"]),\n})\nexport type PluginCoreGroupMember = z.infer<typeof PluginCoreGroupMember>\n\n/**\n * Result of {@linkcode PluginCoreGroupsApi.list}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `groups` | {@linkcode PluginCoreGroupRef}`[]` | Every group in the active project |\n */\nexport const PluginCoreGroupsListResult = z.object({\n groups: z.array(PluginCoreGroupRef),\n})\nexport type PluginCoreGroupsListResult = z.infer<\n typeof PluginCoreGroupsListResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreGroupsApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `groupId` | `string` | The id of the group to read |\n */\nexport const PluginCoreGroupsGetArgs = z.object({\n groupId: z.string(),\n})\nexport type PluginCoreGroupsGetArgs = z.infer<typeof PluginCoreGroupsGetArgs>\n\n/**\n * Result of {@linkcode PluginCoreGroupsApi.get} — the group, or `null` when no\n * group has the given id.\n */\nexport const PluginCoreGroupsGetResult = PluginCoreGroupRef.nullable()\nexport type PluginCoreGroupsGetResult = z.infer<\n typeof PluginCoreGroupsGetResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreGroupsApi.getForComponent}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `componentId` | `ComponentHandle` | The `Component.id` to look up |\n */\nexport const PluginCoreGroupsGetForComponentArgs = z.object({\n componentId: ComponentHandle,\n})\nexport type PluginCoreGroupsGetForComponentArgs = z.infer<\n typeof PluginCoreGroupsGetForComponentArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreGroupsApi.getForComponent} — the innermost\n * group containing the component, or `null`.\n */\nexport const PluginCoreGroupsGetForComponentResult =\n PluginCoreGroupRef.nullable()\nexport type PluginCoreGroupsGetForComponentResult = z.infer<\n typeof PluginCoreGroupsGetForComponentResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreGroupsApi.listMembers}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `groupId` | `string` | The id of the group whose members to read |\n */\nexport const PluginCoreGroupsListMembersArgs = z.object({\n groupId: z.string(),\n})\nexport type PluginCoreGroupsListMembersArgs = z.infer<\n typeof PluginCoreGroupsListMembersArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreGroupsApi.listMembers}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `members` | {@linkcode PluginCoreGroupMember}`[]` | The group's direct members (empty when the group is empty or missing) |\n */\nexport const PluginCoreGroupsListMembersResult = z.object({\n members: z.array(PluginCoreGroupMember),\n})\nexport type PluginCoreGroupsListMembersResult = z.infer<\n typeof PluginCoreGroupsListMembersResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreGroupsApi.isLocked}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `groupId` | `string` | The id of the group to test |\n */\nexport const PluginCoreGroupsIsLockedArgs = z.object({\n groupId: z.string(),\n})\nexport type PluginCoreGroupsIsLockedArgs = z.infer<\n typeof PluginCoreGroupsIsLockedArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreGroupsApi.isLocked} — `true` when the group\n * exists and is locked, else `false`.\n */\nexport const PluginCoreGroupsIsLockedResult = z.boolean()\nexport type PluginCoreGroupsIsLockedResult = z.infer<\n typeof PluginCoreGroupsIsLockedResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreGroupsApi.getBounds}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `groupId` | `string` | The id of the group to measure |\n */\nexport const PluginCoreGroupsGetBoundsArgs = z.object({\n groupId: z.string(),\n})\nexport type PluginCoreGroupsGetBoundsArgs = z.infer<\n typeof PluginCoreGroupsGetBoundsArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreGroupsApi.getBounds} — the group's world-space\n * axis-aligned bounds in internal units, or `null` when the group is empty (has\n * no meshes) or does not exist.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `min` | {@linkcode Vec3Components} | The minimum corner (`x`, `y`, `z`) |\n * | `max` | {@linkcode Vec3Components} | The maximum corner (`x`, `y`, `z`) |\n * | `center` | {@linkcode Vec3Components} | The box center (`x`, `y`, `z`) |\n */\nexport const PluginCoreGroupsGetBoundsResult = z\n .object({\n min: Vec3Components,\n max: Vec3Components,\n center: Vec3Components,\n })\n .nullable()\nexport type PluginCoreGroupsGetBoundsResult = z.infer<\n typeof PluginCoreGroupsGetBoundsResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreGroupsApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `componentIds` | `ComponentHandle[]` | The ids of the components to group (at least one) |\n * | `name` | `string \\| undefined` | Display name for the new group (auto-generated if omitted) |\n */\nexport const PluginCoreGroupsCreateArgs = z.object({\n componentIds: z.array(ComponentHandle).min(1),\n name: z.string().optional(),\n})\nexport type PluginCoreGroupsCreateArgs = z.infer<\n typeof PluginCoreGroupsCreateArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreGroupsApi.create} — the id of the new group.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `groupId` | `string` | The id of the newly created group |\n */\nexport const PluginCoreGroupsCreateResult = z.object({\n groupId: z.string(),\n})\nexport type PluginCoreGroupsCreateResult = z.infer<\n typeof PluginCoreGroupsCreateResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreGroupsApi.update}. Sparse — only the\n * provided fields are changed.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `groupId` | `string` | The id of the group to update |\n * | `name` | `string \\| undefined` | New display name (unchanged if omitted) |\n * | `addComponentIds` | `ComponentHandle[] \\| undefined` | Components to add to the group |\n * | `removeComponentIds` | `ComponentHandle[] \\| undefined` | Components to remove from the group |\n */\nexport const PluginCoreGroupsUpdateArgs = z.object({\n groupId: z.string(),\n name: z.string().optional(),\n addComponentIds: z.array(ComponentHandle).optional(),\n removeComponentIds: z.array(ComponentHandle).optional(),\n})\nexport type PluginCoreGroupsUpdateArgs = z.infer<\n typeof PluginCoreGroupsUpdateArgs\n>\n\n/** Result of {@linkcode PluginCoreGroupsApi.update} — the updated group record. */\nexport const PluginCoreGroupsUpdateResult = PluginCoreGroupRef\nexport type PluginCoreGroupsUpdateResult = z.infer<\n typeof PluginCoreGroupsUpdateResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreGroupsApi.delete}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `groupId` | `string` | The id of the group to dissolve |\n */\nexport const PluginCoreGroupsDeleteArgs = z.object({\n groupId: z.string(),\n})\nexport type PluginCoreGroupsDeleteArgs = z.infer<\n typeof PluginCoreGroupsDeleteArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreGroupsApi.delete} — confirmation that the group\n * was dissolved (its members are preserved).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `deleted` | `true` | Always `true` on success |\n */\nexport const PluginCoreGroupsDeleteResult = z.object({\n deleted: z.literal(true),\n})\nexport type PluginCoreGroupsDeleteResult = z.infer<\n typeof PluginCoreGroupsDeleteResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Buildings — read and edit the buildings of the active project.\n *\n * A **building** is the top of the project's spatial hierarchy: a named container\n * of storeys, positioned by its base elevation. This namespace reads a building's\n * identity and base elevation and lists the storeys it holds; storey detail is\n * read through the entity story surface (`snaptrude.entity.story`).\n *\n * Reads return plain records and never throw for a missing building (`get` and\n * `getActive` return `null`, `list` returns `[]`). Ids are stable public strings.\n *\n * Sub-namespace members typed as optional (`?`) are **authored ahead of the\n * host** — declared so plugins and codegen can see the shape, but kept out of the\n * discovery manifest until the host lands them (at which point they are promoted\n * to required `abstract` members).\n *\n * Accessed via `snaptrude.core.buildings`.\n */\nexport abstract class PluginCoreBuildingsApi {\n constructor() {}\n\n /**\n * List the buildings in the active project.\n *\n * @returns A {@linkcode PluginCoreBuildingsListResult} with a `buildings` array\n * (empty when the project has none).\n *\n * @examplePrompt List all the buildings in my project\n * @examplePrompt How many buildings are in this model?\n * @examplePrompt Show every building with its base elevation\n *\n * # Example\n * ```ts\n * const { buildings } = await snaptrude.core.buildings.list()\n * for (const b of buildings) console.log(b.name, b.baseElevation)\n * ```\n */\n public abstract list(): PluginApiReturn<PluginCoreBuildingsListResult>\n\n /**\n * Get a single building by id.\n *\n * @param buildingId - The id of the building to read.\n * @returns The matching {@linkcode PluginCoreBuildingRef}, or `null` if no\n * building has that id.\n *\n * @examplePrompt Get the building with id blg_1\n * @examplePrompt Look up a single building by its id\n * @examplePrompt What is the base elevation of building blg_2?\n *\n * # Example\n * ```ts\n * const building = await snaptrude.core.buildings.get(\"blg_1\")\n * if (building) console.log(building.name, building.baseElevation)\n * ```\n */\n public abstract get(\n buildingId: string,\n ): PluginApiReturn<PluginCoreBuildingsGetResult>\n\n /**\n * List the storeys of a building.\n *\n * Returns the building's storeys as stable storey ids, in the project's storey\n * order. Read each storey's detail through `snaptrude.entity.story`.\n *\n * @param buildingId - The id of the building whose storeys to list.\n * @returns A {@linkcode PluginCoreBuildingsListStoreysResult} with a `storeyIds`\n * array (empty when the building is missing or has no storeys).\n *\n * @examplePrompt List the storeys in building blg_1\n * @examplePrompt How many floors does this building have?\n * @examplePrompt Get the storey ids of the active building\n *\n * # Example\n * ```ts\n * const { storeyIds } = await snaptrude.core.buildings.listStoreys(\"blg_1\")\n * console.log(`${storeyIds.length} storeys`)\n * ```\n */\n public abstract listStoreys(\n buildingId: string,\n ): PluginApiReturn<PluginCoreBuildingsListStoreysResult>\n\n /**\n * Get the active building.\n *\n * The active building is the one new storeys and edits target. Paired with\n * {@linkcode PluginCoreBuildingsApi.setActive}.\n *\n * @returns A {@linkcode PluginCoreBuildingsGetActiveResult} with the active\n * `buildingId`, or `null` if there is no active building.\n *\n * @examplePrompt Which building is active?\n * @examplePrompt Get the current building\n * @examplePrompt What building am I working in?\n *\n * # Example\n * ```ts\n * const active = await snaptrude.core.buildings.getActive()\n * if (active) console.log(active.buildingId)\n * ```\n */\n public abstract getActive(): PluginApiReturn<PluginCoreBuildingsGetActiveResult>\n\n /**\n * Make a building the active building.\n *\n * Paired with {@linkcode PluginCoreBuildingsApi.getActive}.\n *\n * @param buildingId - The id of the building to activate.\n * @returns The id of the now-active building.\n * @throws If no building has the given id.\n *\n * @examplePrompt Switch to building blg_2\n * @examplePrompt Make this building the active one\n * @examplePrompt Set the active building to blg_1\n *\n * # Example\n * ```ts\n * await snaptrude.core.buildings.setActive(\"blg_2\")\n * ```\n */\n public abstract setActive(\n buildingId: string,\n ): PluginApiReturn<PluginCoreBuildingsSetActiveResult>\n\n /**\n * Create a new building.\n *\n * Adds a named building at the given base elevation (defaults to `0`). The new\n * building starts empty — add storeys through the storeys namespace.\n *\n * @param name - Display name of the new building.\n * @param baseElevation - Base elevation in meters (defaults to `0`).\n * @returns The new building's id (read the full record back with\n * {@linkcode PluginCoreBuildingsApi.get}).\n * @throws If the building could not be created.\n *\n * @examplePrompt Create a building called Tower B\n * @examplePrompt Add a new building at elevation 12 meters\n * @examplePrompt Make a second building named Annex\n *\n * # Example\n * ```ts\n * const { buildingId } = await snaptrude.core.buildings.create(\"Tower B\", 0)\n * ```\n */\n public abstract create(\n name: string,\n baseElevation?: number,\n ): PluginApiReturn<PluginCoreBuildingsCreateResult>\n\n /**\n * Update a building's name and/or base elevation.\n *\n * A **sparse** update: omitted fields are left unchanged.\n *\n * @param buildingId - The id of the building to update.\n * @param options - Any of `name`, `baseElevation`; omitted fields are left\n * unchanged.\n * @returns The updated {@linkcode PluginCoreBuildingRef}.\n * @throws If no building has the given id.\n *\n * @examplePrompt Rename building blg_1 to Tower A\n * @examplePrompt Move the building up to elevation 6 meters\n * @examplePrompt Change the base elevation of blg_2\n *\n * # Example\n * ```ts\n * const building = await snaptrude.core.buildings.update(\"blg_1\", { name: \"Tower A\" })\n * ```\n */\n public abstract update(\n buildingId: string,\n options?: { name?: string; baseElevation?: number },\n ): PluginApiReturn<PluginCoreBuildingsUpdateResult>\n\n /**\n * Copy a building.\n *\n * Copies the building — its storeys, components, and drawing layers — into a new\n * building. `asInstances` controls the copy's geometry: `true` shares the source\n * geometry as instances (low memory), `false` makes independent editable copies\n * (the host defaults to `true`). Optionally override the copy's `name` and\n * `baseElevation`.\n *\n * @param buildingId - The id of the building to copy.\n * @param options - Optional `name`, `baseElevation`, `asInstances` overrides\n * for the copy.\n * @returns The new building's id.\n * @throws If no building has the given id.\n *\n * @examplePrompt Copy building blg_1\n * @examplePrompt Make an independent editable copy of this building\n * @examplePrompt Copy Tower A as instances to save memory\n *\n * # Example\n * ```ts\n * const { buildingId } = await snaptrude.core.buildings.copy(\"blg_1\", {\n * name: \"Tower A Copy\",\n * asInstances: false,\n * })\n * ```\n */\n public abstract copy(\n buildingId: string,\n options?: { name?: string; baseElevation?: number; asInstances?: boolean },\n ): PluginApiReturn<PluginCoreBuildingsCopyResult>\n\n /**\n * Delete a building.\n *\n * **Gated and destructive.** Deleting a building cascades through its meshes,\n * storeys, and the building itself, and removes its saved views — **saved views\n * are not restored on undo.** The project's only remaining building cannot be\n * deleted.\n *\n * @param buildingId - The id of the building to delete.\n * @returns Confirmation that the building was deleted.\n * @throws If no building has the given id, or it is the only building.\n *\n * @examplePrompt Delete building blg_2\n * @examplePrompt Remove the Annex building and everything in it\n * @examplePrompt Delete this building\n *\n * # Example\n * ```ts\n * await snaptrude.core.buildings.delete(\"blg_2\")\n * ```\n */\n public abstract delete(\n buildingId: string,\n ): PluginApiReturn<PluginCoreBuildingsDeleteResult>\n}\n\n/**\n * A building in the active project.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Stable public building id (e.g. `\"blg_1\"`) |\n * | `name` | `string` | Display name |\n * | `baseElevation` | `number` | Base elevation in meters, positive up (default `0`) |\n */\nexport const PluginCoreBuildingRef = z.object({\n id: z.string(),\n name: z.string(),\n baseElevation: z.number(),\n})\nexport type PluginCoreBuildingRef = z.infer<typeof PluginCoreBuildingRef>\n\n/**\n * Result of {@linkcode PluginCoreBuildingsApi.list}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildings` | {@linkcode PluginCoreBuildingRef}`[]` | Every building in the active project |\n */\nexport const PluginCoreBuildingsListResult = z.object({\n buildings: z.array(PluginCoreBuildingRef),\n})\nexport type PluginCoreBuildingsListResult = z.infer<\n typeof PluginCoreBuildingsListResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreBuildingsApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildingId` | `string` | The id of the building to read |\n */\nexport const PluginCoreBuildingsGetArgs = z.object({\n buildingId: z.string(),\n})\nexport type PluginCoreBuildingsGetArgs = z.infer<\n typeof PluginCoreBuildingsGetArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreBuildingsApi.get} — the building, or `null` when\n * no building has the given id.\n */\nexport const PluginCoreBuildingsGetResult = PluginCoreBuildingRef.nullable()\nexport type PluginCoreBuildingsGetResult = z.infer<\n typeof PluginCoreBuildingsGetResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreBuildingsApi.listStoreys}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildingId` | `string` | The id of the building whose storeys to list |\n */\nexport const PluginCoreBuildingsListStoreysArgs = z.object({\n buildingId: z.string(),\n})\nexport type PluginCoreBuildingsListStoreysArgs = z.infer<\n typeof PluginCoreBuildingsListStoreysArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreBuildingsApi.listStoreys}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storeyIds` | `string[]` | The building's storey ids in storey order (empty when missing or none) |\n */\nexport const PluginCoreBuildingsListStoreysResult = z.object({\n storeyIds: z.array(z.string()),\n})\nexport type PluginCoreBuildingsListStoreysResult = z.infer<\n typeof PluginCoreBuildingsListStoreysResult\n>\n\n/**\n * Result of {@linkcode PluginCoreBuildingsApi.getActive} — the active building's\n * id, or `null` when there is no active building.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildingId` | `string` | The id of the active building |\n */\nexport const PluginCoreBuildingsGetActiveResult = z\n .object({\n buildingId: z.string(),\n })\n .nullable()\nexport type PluginCoreBuildingsGetActiveResult = z.infer<\n typeof PluginCoreBuildingsGetActiveResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreBuildingsApi.setActive}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildingId` | `string` | The id of the building to activate |\n */\nexport const PluginCoreBuildingsSetActiveArgs = z.object({\n buildingId: z.string(),\n})\nexport type PluginCoreBuildingsSetActiveArgs = z.infer<\n typeof PluginCoreBuildingsSetActiveArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreBuildingsApi.setActive} — the now-active\n * building's id.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildingId` | `string` | The id of the now-active building |\n */\nexport const PluginCoreBuildingsSetActiveResult = z.object({\n buildingId: z.string(),\n})\nexport type PluginCoreBuildingsSetActiveResult = z.infer<\n typeof PluginCoreBuildingsSetActiveResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreBuildingsApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string` | Display name of the new building |\n * | `baseElevation` | `number \\| undefined` | Base elevation in meters (defaults to `0`) |\n */\nexport const PluginCoreBuildingsCreateArgs = z.object({\n name: z.string(),\n baseElevation: z.number().optional(),\n})\nexport type PluginCoreBuildingsCreateArgs = z.infer<\n typeof PluginCoreBuildingsCreateArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreBuildingsApi.create} — the id of the new\n * building.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildingId` | `string` | The id of the newly created building |\n */\nexport const PluginCoreBuildingsCreateResult = z.object({\n buildingId: z.string(),\n})\nexport type PluginCoreBuildingsCreateResult = z.infer<\n typeof PluginCoreBuildingsCreateResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreBuildingsApi.update}. Sparse — only the\n * provided fields are changed.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildingId` | `string` | The id of the building to update |\n * | `name` | `string \\| undefined` | New display name (unchanged if omitted) |\n * | `baseElevation` | `number \\| undefined` | New base elevation in meters (unchanged if omitted) |\n */\nexport const PluginCoreBuildingsUpdateArgs = z.object({\n buildingId: z.string(),\n name: z.string().optional(),\n baseElevation: z.number().optional(),\n})\nexport type PluginCoreBuildingsUpdateArgs = z.infer<\n typeof PluginCoreBuildingsUpdateArgs\n>\n\n/** Result of {@linkcode PluginCoreBuildingsApi.update} — the updated record. */\nexport const PluginCoreBuildingsUpdateResult = PluginCoreBuildingRef\nexport type PluginCoreBuildingsUpdateResult = z.infer<\n typeof PluginCoreBuildingsUpdateResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreBuildingsApi.copy}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildingId` | `string` | The id of the building to copy |\n * | `name` | `string \\| undefined` | Name for the copy (auto-generated if omitted) |\n * | `baseElevation` | `number \\| undefined` | Base elevation for the copy in meters (source's if omitted) |\n * | `asInstances` | `boolean \\| undefined` | `true` shares source geometry as instances; `false` makes independent copies (host default `true`) |\n */\nexport const PluginCoreBuildingsCopyArgs = z.object({\n buildingId: z.string(),\n name: z.string().optional(),\n baseElevation: z.number().optional(),\n asInstances: z.boolean().optional(),\n})\nexport type PluginCoreBuildingsCopyArgs = z.infer<\n typeof PluginCoreBuildingsCopyArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreBuildingsApi.copy} — the id of the new\n * building.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildingId` | `string` | The id of the copied building |\n */\nexport const PluginCoreBuildingsCopyResult = z.object({\n buildingId: z.string(),\n})\nexport type PluginCoreBuildingsCopyResult = z.infer<\n typeof PluginCoreBuildingsCopyResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreBuildingsApi.delete}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildingId` | `string` | The id of the building to delete |\n */\nexport const PluginCoreBuildingsDeleteArgs = z.object({\n buildingId: z.string(),\n})\nexport type PluginCoreBuildingsDeleteArgs = z.infer<\n typeof PluginCoreBuildingsDeleteArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreBuildingsApi.delete} — confirmation that the\n * building was deleted.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `deleted` | `true` | Always `true` on success |\n */\nexport const PluginCoreBuildingsDeleteResult = z.object({\n deleted: z.literal(true),\n})\nexport type PluginCoreBuildingsDeleteResult = z.infer<\n typeof PluginCoreBuildingsDeleteResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Layers — read and toggle the drawing/reference layers of a storey.\n *\n * These are the **drawing/reference** layers shown in the storey's Layers panel —\n * the surfaces you sketch on and the imported underlays (CAD, PDF, images,\n * terrain). They are **not** wall/floor construction-assembly material layers,\n * which are a property of the built element, not this namespace.\n *\n * Reads return plain records and never throw for a missing layer (`get` and\n * `getActive` return `null`, `list` returns `[]`).\n *\n * v1 exposes reads plus visibility edits and the active-layer switch.\n * Creating and deleting layers are intentionally not part of this contract yet.\n *\n * Sub-namespace members typed as optional (`?`) are **authored ahead of the\n * host** — declared so plugins and codegen can see the shape, but kept out of the\n * discovery manifest until the host lands them (at which point they are promoted\n * to required `abstract` members).\n *\n * Accessed via `snaptrude.core.layers`.\n */\nexport abstract class PluginCoreLayersApi {\n constructor() {}\n\n /**\n * List the drawing layers of a storey.\n *\n * Optionally filter to a single {@linkcode PluginCoreLayerType}.\n *\n * @param storeyId - The storey whose layers to read.\n * @param layerType - Optional {@linkcode PluginCoreLayerType} filter.\n * @returns A {@linkcode PluginCoreLayersListResult} with a `layers` array\n * (empty when the storey is missing or has no matching layers).\n *\n * @examplePrompt List the drawing layers on this storey\n * @examplePrompt Show all the PDF underlays on storey st_2\n * @examplePrompt What CAD layers are on the ground floor?\n *\n * # Example\n * ```ts\n * const { layers } = await snaptrude.core.layers.list(\"st_2\")\n * for (const l of layers) console.log(l.name, l.layerType, l.hidden)\n * ```\n */\n public abstract list(\n storeyId: string,\n layerType?: PluginCoreLayerType,\n ): PluginApiReturn<PluginCoreLayersListResult>\n\n /**\n * Get a single drawing layer by id.\n *\n * @param layerId - The id of the layer to read.\n * @returns The matching {@linkcode PluginCoreLayer}, or `null` if no layer has\n * that id.\n *\n * @examplePrompt Get the drawing layer with id ly_5\n * @examplePrompt Is layer ly_5 hidden or locked?\n * @examplePrompt Look up a single drawing layer by its id\n *\n * # Example\n * ```ts\n * const layer = await snaptrude.core.layers.get(\"ly_5\")\n * if (layer) console.log(layer.name, layer.hidden, layer.locked)\n * ```\n */\n public abstract get(\n layerId: string,\n ): PluginApiReturn<PluginCoreLayersGetResult>\n\n /**\n * Get the active drawing layer of a storey.\n *\n * The active layer is the one new sketch geometry is drawn onto. Paired with\n * {@linkcode PluginCoreLayersApi.setActive}.\n *\n * @param storeyId - The storey whose active layer to read.\n * @returns The active {@linkcode PluginCoreLayer}, or `null` if the storey is\n * missing or has no active layer.\n *\n * @examplePrompt Which drawing layer is active on this storey?\n * @examplePrompt Get the current layer on storey st_2\n * @examplePrompt What layer am I drawing on?\n *\n * # Example\n * ```ts\n * const active = await snaptrude.core.layers.getActive(\"st_2\")\n * if (active) console.log(active.name)\n * ```\n */\n public abstract getActive(\n storeyId: string,\n ): PluginApiReturn<PluginCoreLayersGetActiveResult>\n\n /**\n * Make a drawing layer the active layer of its storey.\n *\n * Paired with {@linkcode PluginCoreLayersApi.getActive}.\n *\n * @param layerId - The id of the layer to activate.\n * @returns The id of the now-active layer.\n * @throws If no layer has the given id.\n *\n * @examplePrompt Draw on layer ly_5\n * @examplePrompt Make this the active layer\n * @examplePrompt Switch the active layer to the CAD underlay\n *\n * # Example\n * ```ts\n * await snaptrude.core.layers.setActive(\"ly_5\")\n * ```\n */\n public abstract setActive(\n layerId: string,\n ): PluginApiReturn<PluginCoreLayersSetActiveResult>\n\n /**\n * Update a drawing layer's visibility.\n *\n * A **sparse** update: omit `hidden` to leave it unchanged. This edit is **not\n * undoable**. Locking and renaming are not exposed — layer `locked` is a\n * read-only status here (setting it at runtime does not lock the live meshes or\n * flip the panel padlock until a reload), and a rename cascades to every member\n * mesh's `layerName`, a corruption hazard.\n *\n * @param layerId - The id of the layer to update.\n * @param hidden - New hidden state (unchanged if omitted).\n * @returns The updated {@linkcode PluginCoreLayer}.\n * @throws If no layer has the given id.\n *\n * @examplePrompt Hide the PDF underlay layer\n * @examplePrompt Show the CAD layer again\n * @examplePrompt Hide layer ly_5\n *\n * # Example\n * ```ts\n * const layer = await snaptrude.core.layers.update(\"ly_5\", true)\n * ```\n */\n public abstract update(\n layerId: string,\n hidden?: boolean,\n ): PluginApiReturn<PluginCoreLayersUpdateResult>\n}\n\n/**\n * The kind of a drawing layer.\n *\n * Author-drawable kinds (`floor`, `wall`, `ceiling`, `rough`, `default`) plus\n * read-only imported underlays (`image`, `cad`, `pdf`, `terrain`, `buildings`).\n */\nexport const PluginCoreLayerType = z.enum([\n \"floor\",\n \"wall\",\n \"ceiling\",\n \"rough\",\n \"default\",\n \"image\",\n \"cad\",\n \"pdf\",\n \"terrain\",\n \"buildings\",\n])\nexport type PluginCoreLayerType = z.infer<typeof PluginCoreLayerType>\n\n/**\n * A drawing/reference layer on a storey.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Stable public layer id (e.g. `\"ly_5\"`) |\n * | `name` | `string` | Display name |\n * | `layerType` | {@linkcode PluginCoreLayerType} | The layer's kind |\n * | `storeyId` | `string` | The stable id of the storey this layer belongs to |\n * | `buildingId` | `string` | The stable id of the building this layer belongs to |\n * | `hidden` | `boolean` | Whether the layer is hidden |\n * | `locked` | `boolean` | Whether the layer is locked against edits |\n * | `contentSummary` | `object` | A summary of what the layer holds (see below) |\n *\n * `contentSummary`:\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `hasFloorplan` | `boolean` | Whether the layer holds drawn floorplan geometry |\n * | `pdfCount` | `number` | Number of PDF underlays on the layer |\n * | `hasTerrain` | `boolean` | Whether the layer holds terrain |\n */\nexport const PluginCoreLayer = z.object({\n id: z.string(),\n name: z.string(),\n layerType: PluginCoreLayerType,\n storeyId: z.string(),\n buildingId: z.string(),\n hidden: z.boolean(),\n locked: z.boolean(),\n contentSummary: z.object({\n hasFloorplan: z.boolean(),\n pdfCount: z.number().int(),\n hasTerrain: z.boolean(),\n }),\n})\nexport type PluginCoreLayer = z.infer<typeof PluginCoreLayer>\n\n/**\n * Arguments for {@linkcode PluginCoreLayersApi.list}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storeyId` | `string` | The storey whose layers to read |\n * | `layerType` | {@linkcode PluginCoreLayerType}` \\| undefined` | Optional layer-type filter |\n */\nexport const PluginCoreLayersListArgs = z.object({\n storeyId: z.string(),\n layerType: PluginCoreLayerType.optional(),\n})\nexport type PluginCoreLayersListArgs = z.infer<\n typeof PluginCoreLayersListArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreLayersApi.list}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `layers` | {@linkcode PluginCoreLayer}`[]` | The storey's drawing layers (empty when missing or none match) |\n */\nexport const PluginCoreLayersListResult = z.object({\n layers: z.array(PluginCoreLayer),\n})\nexport type PluginCoreLayersListResult = z.infer<\n typeof PluginCoreLayersListResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreLayersApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `layerId` | `string` | The id of the layer to read |\n */\nexport const PluginCoreLayersGetArgs = z.object({\n layerId: z.string(),\n})\nexport type PluginCoreLayersGetArgs = z.infer<\n typeof PluginCoreLayersGetArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreLayersApi.get} — the layer, or `null`\n * when no layer has the given id.\n */\nexport const PluginCoreLayersGetResult = PluginCoreLayer.nullable()\nexport type PluginCoreLayersGetResult = z.infer<\n typeof PluginCoreLayersGetResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreLayersApi.getActive}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storeyId` | `string` | The storey whose active layer to read |\n */\nexport const PluginCoreLayersGetActiveArgs = z.object({\n storeyId: z.string(),\n})\nexport type PluginCoreLayersGetActiveArgs = z.infer<\n typeof PluginCoreLayersGetActiveArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreLayersApi.getActive} — the active layer,\n * or `null` when the storey is missing or has no active layer.\n */\nexport const PluginCoreLayersGetActiveResult = PluginCoreLayer.nullable()\nexport type PluginCoreLayersGetActiveResult = z.infer<\n typeof PluginCoreLayersGetActiveResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreLayersApi.setActive}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `layerId` | `string` | The id of the layer to activate |\n */\nexport const PluginCoreLayersSetActiveArgs = z.object({\n layerId: z.string(),\n})\nexport type PluginCoreLayersSetActiveArgs = z.infer<\n typeof PluginCoreLayersSetActiveArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreLayersApi.setActive} — the now-active\n * layer's id.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `layerId` | `string` | The id of the now-active layer |\n */\nexport const PluginCoreLayersSetActiveResult = z.object({\n layerId: z.string(),\n})\nexport type PluginCoreLayersSetActiveResult = z.infer<\n typeof PluginCoreLayersSetActiveResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreLayersApi.update}. Sparse — only the\n * provided fields are changed.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `layerId` | `string` | The id of the layer to update |\n * | `hidden` | `boolean \\| undefined` | New hidden state (unchanged if omitted) |\n */\nexport const PluginCoreLayersUpdateArgs = z.object({\n layerId: z.string(),\n hidden: z.boolean().optional(),\n})\nexport type PluginCoreLayersUpdateArgs = z.infer<\n typeof PluginCoreLayersUpdateArgs\n>\n\n/** Result of {@linkcode PluginCoreLayersApi.update} — the updated layer. */\nexport const PluginCoreLayersUpdateResult = PluginCoreLayer\nexport type PluginCoreLayersUpdateResult = z.infer<\n typeof PluginCoreLayersUpdateResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\nimport { ComponentHandle } from \"../../handles\"\n\n/**\n * Tags — read and edit the tag catalog and its assignments.\n *\n * A **tag** is a colored label that lives in a **category**; a space carries at\n * most one tag per category. This namespace is the catalog + assignment surface:\n * the categories and tags themselves, which components carry which tags, and the\n * assign/unassign operations. Tags attach to **Mass and Floor spaces only**.\n *\n * **Reserved sentinels.** The built-in **`DEPARTMENT`** category is owned by the\n * program layer — it and the tags inside it are read-only here; create/update/\n * delete reject it and direct you to {@linkcode PluginProgramApi}`.departments`.\n * Every category also has a built-in **`DEFAULT`** tag that cannot be deleted;\n * unassigning resets a component's category slot back to `DEFAULT` (a component\n * is never left with a blank slot).\n *\n * Reads return plain records and never throw for a miss (`get*` return `null`,\n * `list*` return `[]`). Ids are stable public strings.\n *\n * Sub-namespace members typed as optional (`?`) are **authored ahead of the\n * host** — declared so plugins and codegen can see the shape, but kept out of the\n * discovery manifest until the host lands them (at which point they are promoted\n * to required `abstract` members).\n *\n * Accessed via `snaptrude.core.tags`.\n */\nexport abstract class PluginCoreTagsApi {\n constructor() {}\n\n /**\n * List the tag categories.\n *\n * @returns A {@linkcode PluginCoreTagsListCategoriesResult} with a `categories`\n * array (empty when there are none), including the reserved `DEPARTMENT`\n * category.\n *\n * @examplePrompt List all the tag categories\n * @examplePrompt What tag categories do I have?\n * @examplePrompt Show every category and its tags\n *\n * # Example\n * ```ts\n * const { categories } = await snaptrude.core.tags.listCategories()\n * for (const c of categories) console.log(c.name, c.tagIds.length)\n * ```\n */\n public abstract listCategories(): PluginApiReturn<PluginCoreTagsListCategoriesResult>\n\n /**\n * Get a single tag category by id.\n *\n * @param categoryId - The id of the category to read.\n * @returns The matching {@linkcode PluginCoreTagCategory}, or `null` if no\n * category has that id.\n *\n * @examplePrompt Get the tag category with id cat_3\n * @examplePrompt Look up a category by its id\n * @examplePrompt Which tags are in this category?\n *\n * # Example\n * ```ts\n * const category = await snaptrude.core.tags.getCategory(\"cat_3\")\n * if (category) console.log(category.name, category.tagIds)\n * ```\n */\n public abstract getCategory(\n categoryId: string,\n ): PluginApiReturn<PluginCoreTagsGetCategoryResult>\n\n /**\n * List tags, optionally within one category.\n *\n * @param categoryId - Optional category filter; omit to list every tag.\n * @returns A {@linkcode PluginCoreTagsListResult} with a `tags` array (empty\n * when there are none).\n *\n * @examplePrompt List every tag in the project\n * @examplePrompt Show the tags in category cat_3\n * @examplePrompt What tags are available?\n *\n * # Example\n * ```ts\n * const { tags } = await snaptrude.core.tags.list(\"cat_3\")\n * for (const t of tags) console.log(t.name, t.color)\n * ```\n */\n public abstract list(\n categoryId?: string,\n ): PluginApiReturn<PluginCoreTagsListResult>\n\n /**\n * Get a single tag by id.\n *\n * @param tagId - The id of the tag to read.\n * @returns The matching {@linkcode PluginCoreTag}, or `null` if no tag has that\n * id.\n *\n * @examplePrompt Get the tag with id tag_9\n * @examplePrompt Look up a single tag by its id\n * @examplePrompt What color is this tag?\n *\n * # Example\n * ```ts\n * const tag = await snaptrude.core.tags.get(\"tag_9\")\n * if (tag) console.log(tag.name, tag.color)\n * ```\n */\n public abstract get(\n tagId: string,\n ): PluginApiReturn<PluginCoreTagsGetResult>\n\n /**\n * List the tags carried by a component.\n *\n * Returns one entry per category the component is tagged in, each carrying the\n * category and tag names and the tag color.\n *\n * @param componentId - The `Component.id` to read.\n * @returns A {@linkcode PluginCoreTagsGetTagsForComponentResult} with a `tags`\n * array (empty when the component has none or does not exist).\n *\n * @examplePrompt What tags does this space have?\n * @examplePrompt List the tags on component cmp_42\n * @examplePrompt Show the labels applied to this room\n *\n * # Example\n * ```ts\n * const { tags } = await snaptrude.core.tags.getTagsForComponent(\"cmp_42\")\n * for (const t of tags) console.log(t.categoryName, t.tagName)\n * ```\n */\n public abstract getTagsForComponent(\n componentId: ComponentHandle,\n ): PluginApiReturn<PluginCoreTagsGetTagsForComponentResult>\n\n /**\n * List the components carrying a given tag or category.\n *\n * Provide **exactly one** of `tagId` (components with that specific tag) or\n * `categoryId` (components carrying any non-default tag in that category). With\n * `categoryId`, pass `untagged: true` to instead return the components that have\n * **no** non-default tag in that category. `untagged` is valid only alongside\n * `categoryId`.\n *\n * @param filter - A {@linkcode PluginCoreTagsListComponentsArgs} filter with\n * exactly one of `tagId`, `categoryId`, plus optional `untagged` (with\n * `categoryId`).\n * @returns A {@linkcode PluginCoreTagsListComponentsResult} with a\n * `componentIds` array (empty when none match).\n *\n * @examplePrompt Which spaces have the tag tag_9?\n * @examplePrompt List every component tagged in category cat_3\n * @examplePrompt Which spaces are untagged in the Occupancy category?\n *\n * # Example\n * ```ts\n * const { componentIds } = await snaptrude.core.tags.listComponents({ tagId: \"tag_9\" })\n * console.log(`${componentIds.length} components`)\n * ```\n */\n public abstract listComponents(\n filter: { tagId?: string; categoryId?: string; untagged?: boolean },\n ): PluginApiReturn<PluginCoreTagsListComponentsResult>\n\n /**\n * Create a new tag category.\n *\n * @param name - Display name of the new category.\n * @returns The new {@linkcode PluginCoreTagCategory}.\n * @throws If the name collides with the reserved `DEPARTMENT` category, or the\n * category could not be created.\n *\n * @examplePrompt Create a tag category called Fire Rating\n * @examplePrompt Add a new category named Zone\n * @examplePrompt Make a category for occupancy type\n *\n * # Example\n * ```ts\n * const category = await snaptrude.core.tags.createCategory(\"Fire Rating\")\n * ```\n */\n public abstract createCategory(\n name: string,\n ): PluginApiReturn<PluginCoreTagsCreateCategoryResult>\n\n /**\n * Rename a tag category.\n *\n * @param categoryId - The id of the category to rename.\n * @param name - The category's new display name.\n * @returns The updated {@linkcode PluginCoreTagCategory}.\n * @throws If no category has the given id, or it is the reserved `DEPARTMENT`\n * category.\n *\n * @examplePrompt Rename category cat_3 to Occupancy\n * @examplePrompt Change the name of this tag category\n * @examplePrompt Update the Zone category's name\n *\n * # Example\n * ```ts\n * const category = await snaptrude.core.tags.updateCategory(\"cat_3\", \"Occupancy\")\n * ```\n */\n public abstract updateCategory(\n categoryId: string,\n name: string,\n ): PluginApiReturn<PluginCoreTagsUpdateCategoryResult>\n\n /**\n * Delete a tag category and all its tags.\n *\n * **Non-undoable.** Every component tagged in this category is reset to the\n * category's `DEFAULT`; the result reports how many tags were removed and how\n * many components were reset.\n *\n * @param categoryId - The id of the category to delete.\n * @returns The impact counts (`deletedTagCount`, `resetComponentCount`).\n * @throws If no category has the given id, or it is the reserved `DEPARTMENT`\n * category.\n *\n * @examplePrompt Delete the Zone tag category\n * @examplePrompt Remove category cat_3 and all its tags\n * @examplePrompt Delete this category\n *\n * # Example\n * ```ts\n * const { deletedTagCount } = await snaptrude.core.tags.deleteCategory(\"cat_3\")\n * ```\n */\n public abstract deleteCategory(\n categoryId: string,\n ): PluginApiReturn<PluginCoreTagsDeleteCategoryResult>\n\n /**\n * Create a new tag in a category.\n *\n * @param categoryId - The category the new tag belongs to.\n * @param name - Display name of the new tag.\n * @param color - Optional CSS hex color string (auto-assigned if omitted).\n * @returns The new {@linkcode PluginCoreTag}.\n * @throws If no category has the given id, or it is the reserved `DEPARTMENT`\n * category.\n *\n * @examplePrompt Add a tag called 2-hour to the Fire Rating category\n * @examplePrompt Create a red High Priority tag in category cat_3\n * @examplePrompt Make a new tag named Retail\n *\n * # Example\n * ```ts\n * const tag = await snaptrude.core.tags.create(\"cat_3\", \"Retail\", \"#b5e1dc\")\n * ```\n */\n public abstract create(\n categoryId: string,\n name: string,\n color?: string,\n ): PluginApiReturn<PluginCoreTagsCreateResult>\n\n /**\n * Update a tag's name and/or color.\n *\n * A **sparse** update: omitted fields are left unchanged.\n *\n * @param tagId - The id of the tag to update.\n * @param options - Any of `name`, `color`; omitted fields are left unchanged.\n * @returns The updated {@linkcode PluginCoreTag}.\n * @throws If no tag has the given id, or it belongs to the reserved\n * `DEPARTMENT` category.\n *\n * @examplePrompt Rename tag tag_9 to Retail\n * @examplePrompt Change this tag's color to #ff8800\n * @examplePrompt Recolor the High Priority tag\n *\n * # Example\n * ```ts\n * const tag = await snaptrude.core.tags.update(\"tag_9\", { name: \"Retail\" })\n * ```\n */\n public abstract update(\n tagId: string,\n options?: { name?: string; color?: string },\n ): PluginApiReturn<PluginCoreTagsUpdateResult>\n\n /**\n * Delete a tag.\n *\n * **Non-undoable.** Every component carrying this tag is reset to its\n * category's `DEFAULT`; the result reports how many components were reset. The\n * built-in `DEFAULT` tag of a category cannot be deleted.\n *\n * @param tagId - The id of the tag to delete.\n * @returns The impact count (`resetComponentCount`).\n * @throws If no tag has the given id, it is a `DEFAULT` tag, or it belongs to\n * the reserved `DEPARTMENT` category.\n *\n * @examplePrompt Delete the Retail tag\n * @examplePrompt Remove tag tag_9\n * @examplePrompt Delete this label\n *\n * # Example\n * ```ts\n * const { resetComponentCount } = await snaptrude.core.tags.delete(\"tag_9\")\n * ```\n */\n public abstract delete(\n tagId: string,\n ): PluginApiReturn<PluginCoreTagsDeleteResult>\n\n /**\n * Assign a tag to components, creating the category and tag if needed.\n *\n * Resolves `tagName` within the category named `categoryName`: if the category\n * or the tag does not exist yet it is created, otherwise the existing one is\n * reused. The resolved tag is then applied to each taggable component (Mass/Floor\n * spaces) — resolve-or-create and assign are **one atomic, undoable action**.\n * Because a component carries one tag per category, this replaces any existing\n * tag from that category. Components that are locked, not taggable, or not found\n * are returned in `skipped` with a reason — never silently dropped. Rejects the\n * reserved `DEPARTMENT` category.\n *\n * @param componentIds - The components to tag (at least one).\n * @param categoryName - The tag category; created if it does not exist (not\n * `DEPARTMENT`).\n * @param tagName - The tag within the category; created if it does not exist,\n * else reused.\n * @returns A {@linkcode PluginCoreTagsAssignResult} — the resolved\n * `categoryId`/`tagId`, whether each was created, and the `assigned`/`skipped`\n * split.\n * @throws If `categoryName` is the reserved `DEPARTMENT` category.\n *\n * @examplePrompt Tag the selected spaces as Retail in the Zone category\n * @examplePrompt Tag these rooms High Priority, creating the tag if it doesn't exist\n * @examplePrompt Put cmp_1 and cmp_2 in Zone / Retail\n *\n * # Example\n * ```ts\n * const { tagId, tagCreated, assigned } = await snaptrude.core.tags.assign(\n * [\"cmp_1\", \"cmp_2\"],\n * \"Zone\",\n * \"Retail\",\n * )\n * ```\n */\n public abstract assign(\n componentIds: ComponentHandle[],\n categoryName: string,\n tagName: string,\n ): PluginApiReturn<PluginCoreTagsAssignResult>\n\n /**\n * Clear a category's tag from components.\n *\n * Resets each component's slot for the given category back to `DEFAULT` (a\n * component always has a `DEFAULT` — the field is never blanked). Components\n * that are locked, not taggable, or not found are returned in `skipped`.\n *\n * @param categoryId - The category slot to reset to default.\n * @param componentIds - The components to clear (at least one).\n * @returns A {@linkcode PluginCoreAssignOutcome} splitting `assigned` (reset to\n * default) from `skipped`.\n * @throws If no category has the given id.\n *\n * @examplePrompt Remove the Occupancy tag from the selected spaces\n * @examplePrompt Clear category cat_3 on components cmp_1 and cmp_2\n * @examplePrompt Untag these rooms in the Zone category\n *\n * # Example\n * ```ts\n * await snaptrude.core.tags.unassign(\"cat_3\", [\"cmp_1\", \"cmp_2\"])\n * ```\n */\n public abstract unassign(\n categoryId: string,\n componentIds: ComponentHandle[],\n ): PluginApiReturn<PluginCoreTagsUnassignResult>\n}\n\n/**\n * A tag category — a named slot that holds a set of mutually-exclusive tags.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Stable public category id |\n * | `name` | `string` | Display name |\n * | `tagIds` | `string[]` | Ids of the tags in this category |\n */\nexport const PluginCoreTagCategory = z.object({\n id: z.string(),\n name: z.string(),\n tagIds: z.array(z.string()),\n})\nexport type PluginCoreTagCategory = z.infer<typeof PluginCoreTagCategory>\n\n/**\n * A tag — a colored label within a category.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Stable public tag id |\n * | `categoryId` | `string` | The id of the category this tag belongs to |\n * | `name` | `string` | Display name |\n * | `color` | `string` | CSS hex color string (e.g. `\"#b5e1dc\"`) |\n */\nexport const PluginCoreTag = z.object({\n id: z.string(),\n categoryId: z.string(),\n name: z.string(),\n color: z.string(),\n})\nexport type PluginCoreTag = z.infer<typeof PluginCoreTag>\n\n/**\n * A tag as carried by a component — the category and tag names resolved for\n * display.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `categoryId` | `string` | The category's id |\n * | `categoryName` | `string` | The category's display name |\n * | `tagId` | `string` | The tag's id |\n * | `tagName` | `string` | The tag's display name |\n * | `color` | `string` | The tag's CSS hex color string |\n */\nexport const PluginCoreComponentTag = z.object({\n categoryId: z.string(),\n categoryName: z.string(),\n tagId: z.string(),\n tagName: z.string(),\n color: z.string(),\n})\nexport type PluginCoreComponentTag = z.infer<typeof PluginCoreComponentTag>\n\n/**\n * The outcome of an assign/unassign — which components changed and which were\n * skipped (with a reason).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `assigned` | `string[]` | Ids of the components that were changed |\n * | `skipped` | `{ id: string; reason: \"locked\" \\| \"not-taggable\" \\| \"not-found\" }[]` | Components that were not changed, each with a reason |\n */\nexport const PluginCoreAssignOutcome = z.object({\n assigned: z.array(z.string()),\n skipped: z.array(\n z.object({\n id: z.string(),\n reason: z.enum([\"locked\", \"not-taggable\", \"not-found\"]),\n }),\n ),\n})\nexport type PluginCoreAssignOutcome = z.infer<typeof PluginCoreAssignOutcome>\n\n/**\n * Result of {@linkcode PluginCoreTagsApi.listCategories}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `categories` | {@linkcode PluginCoreTagCategory}`[]` | Every tag category (including the reserved `DEPARTMENT`) |\n */\nexport const PluginCoreTagsListCategoriesResult = z.object({\n categories: z.array(PluginCoreTagCategory),\n})\nexport type PluginCoreTagsListCategoriesResult = z.infer<\n typeof PluginCoreTagsListCategoriesResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.getCategory}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `categoryId` | `string` | The id of the category to read |\n */\nexport const PluginCoreTagsGetCategoryArgs = z.object({\n categoryId: z.string(),\n})\nexport type PluginCoreTagsGetCategoryArgs = z.infer<\n typeof PluginCoreTagsGetCategoryArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreTagsApi.getCategory} — the category, or `null`\n * when no category has the given id.\n */\nexport const PluginCoreTagsGetCategoryResult = PluginCoreTagCategory.nullable()\nexport type PluginCoreTagsGetCategoryResult = z.infer<\n typeof PluginCoreTagsGetCategoryResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.list}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `categoryId` | `string \\| undefined` | Optional category filter; omit to list every tag |\n */\nexport const PluginCoreTagsListArgs = z.object({\n categoryId: z.string().optional(),\n})\nexport type PluginCoreTagsListArgs = z.infer<typeof PluginCoreTagsListArgs>\n\n/**\n * Result of {@linkcode PluginCoreTagsApi.list}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `tags` | {@linkcode PluginCoreTag}`[]` | The matching tags (empty when none) |\n */\nexport const PluginCoreTagsListResult = z.object({\n tags: z.array(PluginCoreTag),\n})\nexport type PluginCoreTagsListResult = z.infer<typeof PluginCoreTagsListResult>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `tagId` | `string` | The id of the tag to read |\n */\nexport const PluginCoreTagsGetArgs = z.object({\n tagId: z.string(),\n})\nexport type PluginCoreTagsGetArgs = z.infer<typeof PluginCoreTagsGetArgs>\n\n/**\n * Result of {@linkcode PluginCoreTagsApi.get} — the tag, or `null` when no tag\n * has the given id.\n */\nexport const PluginCoreTagsGetResult = PluginCoreTag.nullable()\nexport type PluginCoreTagsGetResult = z.infer<typeof PluginCoreTagsGetResult>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.getTagsForComponent}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `componentId` | `ComponentHandle` | The `Component.id` to read |\n */\nexport const PluginCoreTagsGetTagsForComponentArgs = z.object({\n componentId: ComponentHandle,\n})\nexport type PluginCoreTagsGetTagsForComponentArgs = z.infer<\n typeof PluginCoreTagsGetTagsForComponentArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreTagsApi.getTagsForComponent}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `tags` | {@linkcode PluginCoreComponentTag}`[]` | The component's tags, one per tagged category (empty when none) |\n */\nexport const PluginCoreTagsGetTagsForComponentResult = z.object({\n tags: z.array(PluginCoreComponentTag),\n})\nexport type PluginCoreTagsGetTagsForComponentResult = z.infer<\n typeof PluginCoreTagsGetTagsForComponentResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.listComponents}. Provide exactly one\n * of `tagId`, `categoryId`. `untagged` is valid only with `categoryId`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `tagId` | `string \\| undefined` | Components carrying this specific tag |\n * | `categoryId` | `string \\| undefined` | Components carrying any non-default tag in this category |\n * | `untagged` | `boolean \\| undefined` | With `categoryId`, return components with **no** non-default tag in that category instead |\n */\nexport const PluginCoreTagsListComponentsArgs = z\n .object({\n tagId: z.string().optional(),\n categoryId: z.string().optional(),\n untagged: z.boolean().optional(),\n })\n .refine((v) => (v.tagId == null) !== (v.categoryId == null), {\n message: \"Provide exactly one of tagId or categoryId\",\n })\n .refine((v) => v.untagged == null || v.categoryId != null, {\n message: \"untagged is valid only together with categoryId\",\n })\nexport type PluginCoreTagsListComponentsArgs = z.infer<\n typeof PluginCoreTagsListComponentsArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreTagsApi.listComponents}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `componentIds` | `ComponentHandle[]` | Ids of the matching components (empty when none) |\n */\nexport const PluginCoreTagsListComponentsResult = z.object({\n componentIds: z.array(ComponentHandle),\n})\nexport type PluginCoreTagsListComponentsResult = z.infer<\n typeof PluginCoreTagsListComponentsResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.createCategory}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string` | Display name of the new category |\n */\nexport const PluginCoreTagsCreateCategoryArgs = z.object({\n name: z.string(),\n})\nexport type PluginCoreTagsCreateCategoryArgs = z.infer<\n typeof PluginCoreTagsCreateCategoryArgs\n>\n\n/** Result of {@linkcode PluginCoreTagsApi.createCategory} — the new category. */\nexport const PluginCoreTagsCreateCategoryResult = PluginCoreTagCategory\nexport type PluginCoreTagsCreateCategoryResult = z.infer<\n typeof PluginCoreTagsCreateCategoryResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.updateCategory}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `categoryId` | `string` | The id of the category to rename |\n * | `name` | `string` | The category's new display name |\n */\nexport const PluginCoreTagsUpdateCategoryArgs = z.object({\n categoryId: z.string(),\n name: z.string(),\n})\nexport type PluginCoreTagsUpdateCategoryArgs = z.infer<\n typeof PluginCoreTagsUpdateCategoryArgs\n>\n\n/** Result of {@linkcode PluginCoreTagsApi.updateCategory} — the updated category. */\nexport const PluginCoreTagsUpdateCategoryResult = PluginCoreTagCategory\nexport type PluginCoreTagsUpdateCategoryResult = z.infer<\n typeof PluginCoreTagsUpdateCategoryResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.deleteCategory}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `categoryId` | `string` | The id of the category to delete |\n */\nexport const PluginCoreTagsDeleteCategoryArgs = z.object({\n categoryId: z.string(),\n})\nexport type PluginCoreTagsDeleteCategoryArgs = z.infer<\n typeof PluginCoreTagsDeleteCategoryArgs\n>\n\n/**\n * Result of {@linkcode PluginCoreTagsApi.deleteCategory} — the impact of the\n * (non-undoable) delete.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `deletedTagCount` | `number` | Number of tags removed with the category |\n * | `resetComponentCount` | `number` | Number of components reset to their default |\n */\nexport const PluginCoreTagsDeleteCategoryResult = z.object({\n deletedTagCount: z.number().int(),\n resetComponentCount: z.number().int(),\n})\nexport type PluginCoreTagsDeleteCategoryResult = z.infer<\n typeof PluginCoreTagsDeleteCategoryResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `categoryId` | `string` | The category the new tag belongs to |\n * | `name` | `string` | Display name of the new tag |\n * | `color` | `string \\| undefined` | CSS hex color string (auto-assigned if omitted) |\n */\nexport const PluginCoreTagsCreateArgs = z.object({\n categoryId: z.string(),\n name: z.string(),\n color: z.string().optional(),\n})\nexport type PluginCoreTagsCreateArgs = z.infer<typeof PluginCoreTagsCreateArgs>\n\n/** Result of {@linkcode PluginCoreTagsApi.create} — the new tag. */\nexport const PluginCoreTagsCreateResult = PluginCoreTag\nexport type PluginCoreTagsCreateResult = z.infer<\n typeof PluginCoreTagsCreateResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.update}. Sparse — only the provided\n * fields are changed.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `tagId` | `string` | The id of the tag to update |\n * | `name` | `string \\| undefined` | New display name (unchanged if omitted) |\n * | `color` | `string \\| undefined` | New CSS hex color (unchanged if omitted) |\n */\nexport const PluginCoreTagsUpdateArgs = z.object({\n tagId: z.string(),\n name: z.string().optional(),\n color: z.string().optional(),\n})\nexport type PluginCoreTagsUpdateArgs = z.infer<typeof PluginCoreTagsUpdateArgs>\n\n/** Result of {@linkcode PluginCoreTagsApi.update} — the updated tag. */\nexport const PluginCoreTagsUpdateResult = PluginCoreTag\nexport type PluginCoreTagsUpdateResult = z.infer<\n typeof PluginCoreTagsUpdateResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.delete}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `tagId` | `string` | The id of the tag to delete |\n */\nexport const PluginCoreTagsDeleteArgs = z.object({\n tagId: z.string(),\n})\nexport type PluginCoreTagsDeleteArgs = z.infer<typeof PluginCoreTagsDeleteArgs>\n\n/**\n * Result of {@linkcode PluginCoreTagsApi.delete} — the impact of the\n * (non-undoable) delete.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `resetComponentCount` | `number` | Number of components reset to their category default |\n */\nexport const PluginCoreTagsDeleteResult = z.object({\n resetComponentCount: z.number().int(),\n})\nexport type PluginCoreTagsDeleteResult = z.infer<\n typeof PluginCoreTagsDeleteResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.assign}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `componentIds` | `ComponentHandle[]` | The components to tag (at least one) |\n * | `categoryName` | `string` | The tag category; created if it does not exist (not `DEPARTMENT`) |\n * | `tagName` | `string` | The tag within the category; created if it does not exist, else reused |\n */\nexport const PluginCoreTagsAssignArgs = z.object({\n componentIds: z.array(ComponentHandle).min(1),\n categoryName: z.string(),\n tagName: z.string(),\n})\nexport type PluginCoreTagsAssignArgs = z.infer<typeof PluginCoreTagsAssignArgs>\n\n/**\n * Result of {@linkcode PluginCoreTagsApi.assign} — the resolved category/tag, what\n * was created, and the assign outcome.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `categoryId` | `string` | Id of the resolved (or newly created) category |\n * | `tagId` | `string` | Id of the resolved (or newly created) tag |\n * | `categoryCreated` | `boolean` | Whether the category was created by this call |\n * | `tagCreated` | `boolean` | Whether the tag was created by this call |\n * | `assigned` | `string[]` | Ids of the components that were tagged |\n * | `skipped` | `{ id: string; reason: \"locked\" \\| \"not-taggable\" \\| \"not-found\" }[]` | Components not tagged, each with a reason |\n */\nexport const PluginCoreTagsAssignResult = PluginCoreAssignOutcome.extend({\n categoryId: z.string(),\n tagId: z.string(),\n categoryCreated: z.boolean(),\n tagCreated: z.boolean(),\n})\nexport type PluginCoreTagsAssignResult = z.infer<\n typeof PluginCoreTagsAssignResult\n>\n\n/**\n * Arguments for {@linkcode PluginCoreTagsApi.unassign}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `categoryId` | `string` | The category slot to reset to default |\n * | `componentIds` | `ComponentHandle[]` | The components to clear (at least one) |\n */\nexport const PluginCoreTagsUnassignArgs = z.object({\n categoryId: z.string(),\n componentIds: z.array(ComponentHandle).min(1),\n})\nexport type PluginCoreTagsUnassignArgs = z.infer<\n typeof PluginCoreTagsUnassignArgs\n>\n\n/** Result of {@linkcode PluginCoreTagsApi.unassign} — the unassign outcome. */\nexport const PluginCoreTagsUnassignResult = PluginCoreAssignOutcome\nexport type PluginCoreTagsUnassignResult = z.infer<\n typeof PluginCoreTagsUnassignResult\n>\n","import { PluginMathApi } from \"./math\"\nimport { PluginGeomApi } from \"./geom\"\nimport { PluginHistoryApi } from \"./history\"\nimport { PluginUnitsApi } from \"./units\"\nimport { PluginZoomApi } from \"./zoom\"\nimport { PluginProjectApi } from \"./project\"\nimport { PluginCommentApi } from \"./comment\"\nimport { PluginCoreGroupsApi } from \"./groups\"\nimport { PluginCoreBuildingsApi } from \"./buildings\"\nimport { PluginCoreLayersApi } from \"./layers\"\nimport { PluginCoreTagsApi } from \"./tags\"\n\n/**\n * Core primitives and infrastructure used across the plugin API.\n *\n * - {@linkcode PluginCoreApi.math} — Vector and quaternion operations\n * - {@linkcode PluginCoreApi.geom} — Geometry primitives (lines, arcs, curves, profiles)\n * - {@linkcode PluginCoreApi.history} — Undo / redo of committed history entries\n * - {@linkcode PluginCoreApi.units} — Unit-type queries and conversion\n * - {@linkcode PluginCoreApi.zoom} — Camera zoom controls (extents / selection)\n * - {@linkcode PluginCoreApi.project} — Project-level settings and info\n * - {@linkcode PluginCoreApi.comment} — Comments: create, edit, resolve, tag, list\n * - {@linkcode PluginCoreApi.groups} — Read & edit the group hierarchy\n * - {@linkcode PluginCoreApi.buildings} — Read & edit buildings and their storeys\n * - {@linkcode PluginCoreApi.layers} — Read & toggle storey drawing/reference layers\n * - {@linkcode PluginCoreApi.tags} — Tag catalog + assignment\n */\nexport abstract class PluginCoreApi {\n /** Vector and quaternion math utilities. See {@linkcode PluginMathApi}. */\n public abstract math: PluginMathApi\n /** Geometry primitives and constructors. See {@linkcode PluginGeomApi}. */\n public abstract geom: PluginGeomApi\n /** Undo / redo of committed history entries. See {@linkcode PluginHistoryApi}. */\n public abstract history: PluginHistoryApi\n /** Unit-type queries and conversion. See {@linkcode PluginUnitsApi}. */\n public abstract units: PluginUnitsApi\n /** Camera zoom controls. See {@linkcode PluginZoomApi}. */\n public abstract zoom: PluginZoomApi\n /** Project-level settings and info. See {@linkcode PluginProjectApi}. */\n public abstract project: PluginProjectApi\n /** Comments — create, edit, resolve, tag, list. See {@linkcode PluginCommentApi}. */\n public abstract comment: PluginCommentApi\n /** Groups — read & edit the group hierarchy. See {@linkcode PluginCoreGroupsApi}. */\n public abstract groups: PluginCoreGroupsApi\n /** Buildings — read & edit buildings and their storeys. See {@linkcode PluginCoreBuildingsApi}. */\n public abstract buildings: PluginCoreBuildingsApi\n /** Layers — read & toggle storey drawing/reference layers. See {@linkcode PluginCoreLayersApi}. */\n public abstract layers: PluginCoreLayersApi\n /** Tags — tag catalog + assignment. See {@linkcode PluginCoreTagsApi}. */\n public abstract tags: PluginCoreTagsApi\n\n constructor() {}\n}\n\nexport * from \"./math\"\nexport * from \"./geom\"\nexport * from \"./history\"\nexport * from \"./units\"\nexport * from \"./zoom\"\nexport * from \"./project\"\nexport * from \"./comment\"\nexport * from \"./groups\"\nexport * from \"./buildings\"\nexport * from \"./layers\"\nexport * from \"./tags\"\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport {\n ComponentHandle,\n ContourHandle,\n ProfileHandle,\n Vec3Handle,\n} from \"../../../handles\"\nimport {\n PluginSpaceType,\n PluginMassType,\n PluginDepartmentId,\n} from \"../../entity/space\"\n\n/**\n * `design.create.*` — author new scene-committed BIM entities.\n *\n * Every creator takes geometry handles + scalars and returns a\n * {@linkcode ComponentHandle} (or `ComponentHandle[]` for plural creators) — the\n * `Component.id` of the created entity, resolvable across the rest of the\n * `design.*` surface. Creation is an undoable host call; it **throws** on failure\n * (no `Result` wrapper — consistent with `core.geom.create.*`).\n *\n * Footprint objects take a {@linkcode ContourHandle} (outer profile + holes);\n * build one with `snaptrude.core.geom.create.contourFromProfile(s)`.\n *\n * Accessed via `snaptrude.design.create`.\n */\nexport abstract class PluginDesignCreateApi {\n constructor() {}\n\n /**\n * Create a **space** (a room / mass) by extruding a footprint contour upward.\n *\n * The `contour` is the bottom footprint (outer profile + optional holes); it\n * is extruded by `height` along +Y. The space is placed on the active story\n * and assigned a default department unless overridden.\n *\n * @param contour - Bottom footprint (outer + holes)\n * @param height - Extrusion height (Snaptrude units, > 0)\n * @param label - Room label (maps to the space's `room_type`)\n * @param position - Offset from origin (default origin)\n * @param spaceType - Space-type classification (default `Room`)\n * @param massType - Mass-type classification (default `Room`)\n * @param departmentId - Department assignment (default department)\n * @returns the {@linkcode ComponentHandle} of the created space\n * @throws if the contour is invalid or the height is not positive\n *\n * @examplePrompt Create a room called Living Room that's 3m tall from this outline\n * @examplePrompt Add a new space on the current storey using this footprint\n * @examplePrompt Make a bedroom here and assign it to the Residential department\n * @examplePrompt Extrude this closed outline into a 10 foot high room\n * @examplePrompt Can you create a Kitchen space from the sketch I just drew?\n *\n * # Example\n * ```ts\n * const v = snaptrude.core.math.vec3\n * const outer = await snaptrude.core.geom.create.profileFromLinePoints([\n * await v.new(0, 0, 0),\n * await v.new(10, 0, 0),\n * await v.new(10, 0, 8),\n * await v.new(0, 0, 8),\n * ])\n * const contour = await snaptrude.core.geom.create.contourFromProfile(outer)\n * const space = await snaptrude.design.create.space(contour, 3, \"Living\")\n * ```\n */\n public abstract space(\n contour: ContourHandle,\n height: number,\n label?: string,\n position?: Vec3Handle,\n spaceType?: PluginSpaceType,\n massType?: PluginMassType,\n departmentId?: PluginDepartmentId,\n ): PluginApiReturn<ComponentHandle>\n\n /**\n * Create a **mass** — a generic extruded prism (default `massType` \"Generic mass\").\n * Same footprint-extrude path as {@linkcode PluginDesignCreateApi.space}.\n *\n * @param contour - Footprint (outer + holes)\n * @param height - Extrusion height (> 0)\n * @param label - Label (maps to `room_type`)\n * @param position - Offset from origin\n * @param massType - Mass type (default `Generic mass`)\n * @returns the {@linkcode ComponentHandle} of the created mass\n * @throws if the contour is invalid or the height is not positive\n *\n * @examplePrompt Create a generic mass 30m tall from this footprint\n * @examplePrompt Block out a conceptual massing volume for the site\n * @examplePrompt Extrude this shape into a building mass\n * @examplePrompt Add a simple study-model volume at the origin\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(20, 15)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const tower = await snaptrude.design.create.mass(contour, 30, \"Tower A\", undefined, \"Building\")\n * ```\n */\n public abstract mass(\n contour: ContourHandle,\n height: number,\n label?: string,\n position?: Vec3Handle,\n massType?: PluginMassType,\n ): PluginApiReturn<ComponentHandle>\n\n /**\n * Create a **slab** by extruding a footprint contour by `thickness`\n * (default direction: down).\n *\n * @param contour - Footprint (outer + holes)\n * @param thickness - Slab thickness (> 0)\n * @param direction - Extrusion direction (default `\"down\"`)\n * @param slabType - Slab-type classification\n * @returns the {@linkcode ComponentHandle} of the created slab\n * @throws if the contour is invalid or the thickness is not positive\n *\n * @examplePrompt Add a 150mm thick slab under this footprint\n * @examplePrompt Create a floor slab from this outline\n * @examplePrompt Pour a plinth slab over the building footprint\n * @examplePrompt Make a basement slab that extrudes downward\n * @examplePrompt Give this room outline a 6 inch slab\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(12, 10)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const slab = await snaptrude.design.create.slab(contour, 0.15, \"down\", \"Plinth\")\n * ```\n */\n public abstract slab(\n contour: ContourHandle,\n thickness: number,\n direction?: \"up\" | \"down\",\n slabType?: PluginSlabType,\n ): PluginApiReturn<ComponentHandle>\n\n /**\n * Create a **floor** by extruding a footprint contour by `thickness`\n * (extruded upward).\n *\n * @param contour - Footprint (outer + holes)\n * @param thickness - Floor thickness (> 0)\n * @param position - Offset from origin\n * @returns the {@linkcode ComponentHandle} of the created floor\n * @throws if the contour is invalid or the thickness is not positive\n *\n * @examplePrompt Create a floor from this room outline\n * @examplePrompt Add a 100mm thick floor over the footprint\n * @examplePrompt Lay flooring across the selected outline\n * @examplePrompt Put a floor at this position with 150mm thickness\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(5, 4)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const floor = await snaptrude.design.create.floor(contour, 0.1)\n * ```\n */\n public abstract floor(\n contour: ContourHandle,\n thickness: number,\n position?: Vec3Handle,\n ): PluginApiReturn<ComponentHandle>\n\n /**\n * Create a **roof** by extruding a footprint contour by `thickness`. Created\n * flat (extruded downward); pitch/slope is a separate post-creation edit.\n *\n * @param contour - Footprint (outer + holes)\n * @param thickness - Roof-slab thickness (> 0)\n * @returns the {@linkcode ComponentHandle} of the created roof\n * @throws if the contour is invalid or the thickness is not positive\n *\n * @examplePrompt Add a flat roof over the building footprint\n * @examplePrompt Create a roof 200mm thick from this outline\n * @examplePrompt Cover the top storey with a roof slab\n * @examplePrompt Put a roof on this building\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(12, 10)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const roof = await snaptrude.design.create.roof(contour, 0.2)\n * ```\n */\n public abstract roof(\n contour: ContourHandle,\n thickness: number,\n ): PluginApiReturn<ComponentHandle>\n\n /**\n * Create a **ceiling** by extruding a footprint contour by `thickness`, lifted\n * `heightFromFloor` above the floor.\n *\n * @param contour - Footprint (outer + holes)\n * @param thickness - Ceiling thickness (> 0)\n * @param heightFromFloor - Lift above the floor (default 0)\n * @returns the {@linkcode ComponentHandle} of the created ceiling\n * @throws if the contour is invalid or the thickness is not positive\n *\n * @examplePrompt Add a false ceiling 2.7m above the floor\n * @examplePrompt Create a ceiling over this room footprint\n * @examplePrompt Put a dropped ceiling in the living room at 3 metres\n * @examplePrompt Add a 50mm thick ceiling lifted 2800mm from floor level\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(5, 4)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const ceiling = await snaptrude.design.create.ceiling(contour, 0.05, 2.8)\n * ```\n */\n public abstract ceiling(\n contour: ContourHandle,\n thickness: number,\n heightFromFloor?: number,\n ): PluginApiReturn<ComponentHandle>\n\n /**\n * Create a **column** by extruding a cross-section contour upward by `height`\n * from a base `position`.\n *\n * @param position - Base point\n * @param crossSection - Column cross-section footprint\n * @param height - Column height (> 0)\n * @param directionUp - Up axis (default world up)\n * @returns the {@linkcode ComponentHandle} of the created column\n * @throws if the cross-section is invalid or the height is not positive\n *\n * @examplePrompt Add a 3m tall column at this point\n * @examplePrompt Place a column at the grid intersection\n * @examplePrompt Create a 450mm square concrete column 4 metres high\n * @examplePrompt Stand a column up from this base point\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(0.45, 0.45)\n * const crossSection = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const base = await snaptrude.core.math.vec3.new(4, 0, 4)\n * const column = await snaptrude.design.create.column(base, crossSection, 3)\n * ```\n */\n public abstract column(\n position: Vec3Handle,\n crossSection: ContourHandle,\n height: number,\n directionUp?: Vec3Handle,\n ): PluginApiReturn<ComponentHandle>\n\n /**\n * Create a **beam** by extruding a cross-section contour along `direction` by\n * `length`.\n *\n * @param section - Beam cross-section footprint\n * @param length - Beam length along `direction` (> 0)\n * @param direction - Extrusion axis (default world up)\n * @returns the {@linkcode ComponentHandle} of the created beam\n * @throws if the section is invalid or the length is not positive\n *\n * @examplePrompt Add a beam spanning 6 metres between the columns\n * @examplePrompt Create a horizontal beam along the X axis\n * @examplePrompt Run a 300x600 beam across the room\n * @examplePrompt Extrude this cross-section into a 5m long beam\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(0.3, 0.6)\n * const section = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const alongX = await snaptrude.core.math.vec3.new(1, 0, 0)\n * const beam = await snaptrude.design.create.beam(section, 6, alongX)\n * ```\n */\n public abstract beam(\n section: ContourHandle,\n length: number,\n direction?: Vec3Handle,\n ): PluginApiReturn<ComponentHandle>\n\n /**\n * Create a connected run of **walls** from a profile — one wall per curve in\n * the profile's chain, with mitred corners at shared endpoints.\n *\n * @param profile - Ordered curve chain (wall centerlines)\n * @param height - Wall height (default engine default)\n * @param thickness - Wall thickness (default engine default)\n * @returns a {@linkcode ComponentHandle}`[]` (one per wall), in profile order\n * @throws if the profile is empty or wall creation fails\n *\n * @examplePrompt Draw walls along this centerline\n * @examplePrompt Create 3m high, 200mm thick walls from these points\n * @examplePrompt Build a wall run around the room outline\n * @examplePrompt Turn this polyline sketch into walls\n * @examplePrompt Add walls with mitred corners along the path\n *\n * # Example\n * ```ts\n * const v = snaptrude.core.math.vec3\n * const centerlines = await snaptrude.core.geom.create.profileFromLinePoints([\n * await v.new(0, 0, 0),\n * await v.new(8, 0, 0),\n * await v.new(8, 0, 6),\n * ])\n * const walls = await snaptrude.design.create.walls(centerlines, 3, 0.2)\n * ```\n */\n public abstract walls(\n profile: ProfileHandle,\n height?: number,\n thickness?: number,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * Create a **staircase** from a parametric preset, placed at a point.\n *\n * Geometry is procedurally generated from the chosen `preset`; there is no\n * footprint input. Placed on the active structure/story unless overridden.\n *\n * @param preset - The parametric preset to generate\n * @param position - Placement point\n * @param label - Optional label\n * @param structureId - Target structure (default active)\n * @param level - Target level name (default active/`\"01\"`)\n * @returns the {@linkcode ComponentHandle} of the created staircase\n * @throws if the preset is unknown or placement fails\n *\n * @examplePrompt Add a dog-legged staircase at this location\n * @examplePrompt Place a straight stair on level 01\n * @examplePrompt Create an L-shaped staircase in the lobby\n * @examplePrompt Insert a staircase near the entrance\n * @examplePrompt Put amphitheatre steps at these coordinates\n *\n * # Example\n * ```ts\n * const stair = await snaptrude.design.create.staircase(\n * \"dogLegged\",\n * await snaptrude.core.math.vec3.new(5, 0, 5),\n * )\n * ```\n */\n public abstract staircase(\n preset: PluginStaircasePreset,\n position: Vec3Handle,\n label?: string,\n structureId?: string,\n level?: string,\n ): PluginApiReturn<ComponentHandle>\n\n /**\n * Create **reference lines** from a profile — one reference line per curve in\n * the profile's ordered chain. Returns a handle per created line.\n *\n * Optional style (`color`, `thickness`, `style`, `gridTag`) applies to\n * every created line.\n *\n * @param profile - Ordered curve chain (centerlines)\n * @param color - Hex color `\"#RRGGBB\"` (default white)\n * @param thickness - Line thickness (default 1)\n * @param style - Line style (default `SOLID`)\n * @param gridTag - Grid tag label (default `\"A\"`)\n * @returns a {@linkcode ComponentHandle}`[]` (one per curve), in profile order\n * @throws if the profile is empty or creation fails\n *\n * @examplePrompt Draw a reference line between these two points\n * @examplePrompt Add dashed guide lines along this path\n * @examplePrompt Create grid lines tagged A through the plan\n * @examplePrompt Set up construction lines for the column grid\n * @examplePrompt Mark a red reference line across the site\n *\n * # Example\n * ```ts\n * const v = snaptrude.core.math.vec3\n * const profile = await snaptrude.core.geom.create.profileFromLinePoints([\n * await v.new(0, 0, 0),\n * await v.new(10, 0, 0),\n * ])\n * const lines = await snaptrude.design.create.referenceLines(\n * profile,\n * undefined,\n * undefined,\n * \"DASHED\",\n * )\n * ```\n */\n public abstract referenceLines(\n profile: ProfileHandle,\n color?: string,\n thickness?: number,\n style?: PluginReferenceLineStyle,\n gridTag?: string,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * Place a **furniture** item from the project library at a world position.\n *\n * Identified by a **catalog (library) id** — the team object's stable `_id` for\n * project uploads, or the item's `fullName` for the general library. Discover ids\n * with {@linkcode PluginDesignFurnitureApi.listCatalog}. Placement is asynchronous\n * (the source mesh is fetched if not cached) and creates one undo entry.\n *\n * Placed at the item's default rotation; rotate afterward via `design.transform.rotate`\n * on the returned handle (planned namespace).\n *\n * @param catalogId - Library id: team `_id` or general `fullName`\n * @param position - Absolute world placement point\n * @param options - Optional placement options: `label` — instance name\n * (default auto `${name}Ins${n}`); `createNewSourceMesh` — emit a\n * source-mesh creation command (default `true`)\n * @returns the {@linkcode ComponentHandle} of the placed furniture instance\n * @throws if the catalog id is unknown, the source mesh fails to load, or placement fails\n *\n * @examplePrompt Place a chair from the library at this spot\n * @examplePrompt Add a sofa from the furniture catalog to the living room\n * @examplePrompt Drop a desk into the scene at 3, 0, 5\n * @examplePrompt Insert the uploaded bed model in the bedroom\n * @examplePrompt Put a table from my project library here and name it Table-01\n *\n * # Example\n * ```ts\n * const chair = await snaptrude.design.create.furniture(\n * \"6620f1a…\", // from design.furniture.listCatalog()\n * await snaptrude.core.math.vec3.new(3, 0, 5),\n * { label: \"Chair-01\" },\n * )\n * ```\n */\n public abstract furniture(\n catalogId: string,\n position: Vec3Handle,\n options?: { label?: string; createNewSourceMesh?: boolean },\n ): PluginApiReturn<ComponentHandle>\n\n /**\n * **Copy** existing entities, offsetting each copy by `displacement * i` (i = 1…count),\n * source positions preserved. Migrated from the removed `tools.copy`. In `\"instance\"`\n * mode copies stay in the source's instance family where possible; `\"unique\"` makes\n * independent geometry. The created copies become the active selection. Undoable.\n *\n * @param components - Entities to copy (≥1)\n * @param displacement - Per-copy offset as a {@linkcode Vec3Handle} (copy `i` at `displacement * i`)\n * @param options - `count` (copies per component, default 1), `mode` (`\"instance\"` | `\"unique\"`, default `\"instance\"`)\n * @returns the created copies as {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt Copy this room 3 times spaced 6m apart\n * @examplePrompt Duplicate the selected furniture along the X axis\n * @examplePrompt Make 5 copies of this column at 4 metre intervals\n * @examplePrompt Array these walls with a 3m offset\n * @examplePrompt Clone the desk as a unique copy, not an instance\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n * const copies = await snaptrude.design.create.copy([\"space-id\"], vec3.new(6, 0, 0), { count: 3 })\n * ```\n */\n public abstract copy(\n components: ComponentHandle[],\n displacement: Vec3Handle,\n options?: { count?: number; mode?: PluginCopyMode },\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * Create **many spaces** in one undoable operation (bulk plural of {@linkcode space}).\n * Migrated from the removed `entity.space.bulkCreate`. Each item extrudes a contour\n * footprint up `height`. Validate-all-or-throw; one command. For a rectangular\n * (box) space, build the footprint with `core.geom.create.profileRect` →\n * `contourFromProfile`, then pass it as an item.\n *\n * @param items - One {@linkcode PluginCreateSpaceItem} per space to create (≥1)\n * @returns the created spaces as {@linkcode ComponentHandle}`[]`, in input order\n *\n * @examplePrompt Create several rooms at once from these footprints\n * @examplePrompt Generate all the bedrooms in one operation\n * @examplePrompt Bulk create the spaces for this floor plan\n * @examplePrompt Add three rooms with different heights in a single undo step\n *\n * # Example\n * ```ts\n * const rect = await snaptrude.core.geom.create.profileRect(4, 3)\n * const contour = await snaptrude.core.geom.create.contourFromProfile(rect)\n * const [a, b] = await snaptrude.design.create.spaces([\n * { contour, height: 3, label: \"R1\" },\n * { contour, height: 4, label: \"R2\", position: await vec3.new(10, 0, 0) },\n * ])\n * ```\n */\n public abstract spaces(items: PluginCreateSpaceItem[]): PluginApiReturn<ComponentHandle[]>\n}\n\n// ---------------------------------------------------------------------------\n// Enums\n// ---------------------------------------------------------------------------\n\n/**\n * Line style of a reference line (mirrors the engine `ReferenceLineMode` verbatim).\n *\n * | Value | Description |\n * |---|---|\n * | `\"SOLID\"` | Solid line (default) |\n * | `\"DASHED\"` | Dashed line |\n * | `\"DOT_DASH\"` | Dot-dash line |\n */\nexport const PluginReferenceLineStyle = z.enum([\"SOLID\", \"DASHED\", \"DOT_DASH\"])\nexport type PluginReferenceLineStyle = z.infer<typeof PluginReferenceLineStyle>\n\n/**\n * Slab type (mirrors the engine `SLAB_TYPES` values verbatim).\n *\n * | Value | Description |\n * |---|---|\n * | `\"Intermediate Slab\"` | Intermediate floor slab (default) |\n * | `\"Basement Slab\"` | Basement slab |\n * | `\"Plinth\"` | Plinth slab |\n * | `\"Roof\"` | Roof slab |\n */\nexport const PluginSlabType = z.enum([\n \"Intermediate Slab\",\n \"Basement Slab\",\n \"Plinth\",\n \"Roof\",\n])\nexport type PluginSlabType = z.infer<typeof PluginSlabType>\n\n/**\n * A staircase preset — a base type or a named parametric preset. Mirrors the\n * engine `STAIRCASE_PRESETS` / `StaircaseType`. Use the value that matches the\n * shape you want (e.g. `\"straight\"`, `\"dogLegged\"`, `\"lShaped\"`).\n */\nexport const PluginStaircasePreset = z.enum([\n \"straight\",\n \"straightWoLanding\",\n \"straightFlightWoMidLanding\",\n \"dogLegged\",\n \"openWell\",\n \"lShaped\",\n \"3StepLShaped\",\n \"square\",\n \"singleStep\",\n \"plinthLevel\",\n \"amphitheatre\",\n \"connectingStepsToAmphitheatre\",\n \"mezzanineFloorStraight\",\n \"mezzanineFloorDogLegged\",\n \"mezzanineFloorLShaped\",\n \"custom\",\n])\nexport type PluginStaircasePreset = z.infer<typeof PluginStaircasePreset>\n\n// ---------------------------------------------------------------------------\n// space\n// ---------------------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.space}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | Bottom footprint (outer + holes) |\n * | `height` | `number` | Extrusion height (Snaptrude units, > 0) |\n * | `label` | `string`? | Room label (maps to the space's `room_type`) |\n * | `position` | {@linkcode Vec3Handle}? | Offset from origin (default origin) |\n * | `spaceType` | {@linkcode PluginSpaceType}? | Space-type classification (default `Room`) |\n * | `massType` | {@linkcode PluginMassType}? | Mass-type classification (default `Room`) |\n * | `departmentId` | {@linkcode PluginDepartmentId}? | Department assignment (default department) |\n */\nexport const PluginDesignCreateSpaceArgs = z.object({\n contour: ContourHandle,\n height: z.number(),\n label: z.string().optional(),\n position: Vec3Handle.optional(),\n spaceType: PluginSpaceType.optional(),\n massType: PluginMassType.optional(),\n departmentId: PluginDepartmentId.optional(),\n})\nexport type PluginDesignCreateSpaceArgs = z.infer<typeof PluginDesignCreateSpaceArgs>\n\n// ---------------------------------------------------------------------------\n// mass\n// ---------------------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.mass}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | Footprint (outer + holes) |\n * | `height` | `number` | Extrusion height (> 0) |\n * | `label` | `string`? | Label (maps to `room_type`) |\n * | `position` | {@linkcode Vec3Handle}? | Offset from origin |\n * | `massType` | {@linkcode PluginMassType}? | Mass type (default `Generic mass`) |\n */\nexport const PluginDesignCreateMassArgs = z.object({\n contour: ContourHandle,\n height: z.number(),\n label: z.string().optional(),\n position: Vec3Handle.optional(),\n massType: PluginMassType.optional(),\n})\nexport type PluginDesignCreateMassArgs = z.infer<typeof PluginDesignCreateMassArgs>\n\n// ---------------------------------------------------------------------------\n// slab\n// ---------------------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.slab}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | Footprint (outer + holes) |\n * | `thickness` | `number` | Slab thickness (> 0) |\n * | `direction` | `\"up\" \\| \"down\"`? | Extrusion direction (default `\"down\"`) |\n * | `slabType` | {@linkcode PluginSlabType}? | Slab-type classification |\n */\nexport const PluginDesignCreateSlabArgs = z.object({\n contour: ContourHandle,\n thickness: z.number(),\n direction: z.enum([\"up\", \"down\"]).optional(),\n slabType: PluginSlabType.optional(),\n})\nexport type PluginDesignCreateSlabArgs = z.infer<typeof PluginDesignCreateSlabArgs>\n\n// ---------------------------------------------------------------------------\n// floor\n// ---------------------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.floor}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | Footprint (outer + holes) |\n * | `thickness` | `number` | Floor thickness (> 0) |\n * | `position` | {@linkcode Vec3Handle}? | Offset from origin |\n */\nexport const PluginDesignCreateFloorArgs = z.object({\n contour: ContourHandle,\n thickness: z.number(),\n position: Vec3Handle.optional(),\n})\nexport type PluginDesignCreateFloorArgs = z.infer<typeof PluginDesignCreateFloorArgs>\n\n// ---------------------------------------------------------------------------\n// roof\n// ---------------------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.roof}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | Footprint (outer + holes) |\n * | `thickness` | `number` | Roof-slab thickness (> 0) |\n */\nexport const PluginDesignCreateRoofArgs = z.object({\n contour: ContourHandle,\n thickness: z.number(),\n})\nexport type PluginDesignCreateRoofArgs = z.infer<typeof PluginDesignCreateRoofArgs>\n\n// ---------------------------------------------------------------------------\n// ceiling\n// ---------------------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.ceiling}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | Footprint (outer + holes) |\n * | `thickness` | `number` | Ceiling thickness (> 0) |\n * | `heightFromFloor` | `number`? | Lift above the floor (default 0) |\n */\nexport const PluginDesignCreateCeilingArgs = z.object({\n contour: ContourHandle,\n thickness: z.number(),\n heightFromFloor: z.number().optional(),\n})\nexport type PluginDesignCreateCeilingArgs = z.infer<typeof PluginDesignCreateCeilingArgs>\n\n// ---------------------------------------------------------------------------\n// column\n// ---------------------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.column}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `position` | {@linkcode Vec3Handle} | Base point |\n * | `crossSection` | {@linkcode ContourHandle} | Column cross-section footprint |\n * | `height` | `number` | Column height (> 0) |\n * | `directionUp` | {@linkcode Vec3Handle}? | Up axis (default world up) |\n */\nexport const PluginDesignCreateColumnArgs = z.object({\n position: Vec3Handle,\n crossSection: ContourHandle,\n height: z.number(),\n directionUp: Vec3Handle.optional(),\n})\nexport type PluginDesignCreateColumnArgs = z.infer<typeof PluginDesignCreateColumnArgs>\n\n// ---------------------------------------------------------------------------\n// beam\n// ---------------------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.beam}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `section` | {@linkcode ContourHandle} | Beam cross-section footprint |\n * | `length` | `number` | Beam length along `direction` (> 0) |\n * | `direction` | {@linkcode Vec3Handle}? | Extrusion axis (default world up) |\n */\nexport const PluginDesignCreateBeamArgs = z.object({\n section: ContourHandle,\n length: z.number(),\n direction: Vec3Handle.optional(),\n})\nexport type PluginDesignCreateBeamArgs = z.infer<typeof PluginDesignCreateBeamArgs>\n\n// ---------------------------------------------------------------------------\n// walls\n// ---------------------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.walls}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | Ordered curve chain (wall centerlines) |\n * | `height` | `number`? | Wall height (default engine default) |\n * | `thickness` | `number`? | Wall thickness (default engine default) |\n */\nexport const PluginDesignCreateWallsArgs = z.object({\n profile: ProfileHandle,\n height: z.number().optional(),\n thickness: z.number().optional(),\n})\nexport type PluginDesignCreateWallsArgs = z.infer<typeof PluginDesignCreateWallsArgs>\n\n// ---------------------------------------------------------------------------\n// staircase\n// ---------------------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.staircase}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `preset` | {@linkcode PluginStaircasePreset} | The parametric preset to generate |\n * | `position` | {@linkcode Vec3Handle} | Placement point |\n * | `label` | `string`? | Optional label |\n * | `structureId` | `string`? | Target structure (default active) |\n * | `level` | `string`? | Target level name (default active/`\"01\"`) |\n */\nexport const PluginDesignCreateStaircaseArgs = z.object({\n preset: PluginStaircasePreset,\n position: Vec3Handle,\n label: z.string().optional(),\n structureId: z.string().optional(),\n level: z.string().optional(),\n})\nexport type PluginDesignCreateStaircaseArgs = z.infer<\n typeof PluginDesignCreateStaircaseArgs\n>\n\n// ---------------------------------------------------------------------------\n// furniture\n// ---------------------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.furniture}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `catalogId` | `string` | Library id: team `_id` or general `fullName` |\n * | `position` | {@linkcode Vec3Handle} | Absolute world placement point |\n * | `label` | `string`? | Instance name (default auto `${name}Ins${n}`) |\n * | `createNewSourceMesh` | `boolean`? | Emit a source-mesh creation command (default `true`) |\n */\nexport const PluginDesignCreateFurnitureArgs = z.object({\n catalogId: z.string().min(1),\n position: Vec3Handle,\n label: z.string().optional(),\n createNewSourceMesh: z.boolean().optional(),\n})\nexport type PluginDesignCreateFurnitureArgs = z.infer<\n typeof PluginDesignCreateFurnitureArgs\n>\n// TRANSPORT: positional signature shipped —\n// furniture(catalogId: string, position: Vec3Handle, options?: { label?, createNewSourceMesh? })\n\n// ---------------------------------------------------------------------------\n// referenceLines\n// ---------------------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.referenceLines}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | Ordered curve chain (centerlines) |\n * | `color` | `string`? | Hex color `\"#RRGGBB\"` (default white) |\n * | `thickness` | `number`? | Line thickness (default 1) |\n * | `style` | {@linkcode PluginReferenceLineStyle}? | Line style (default `SOLID`) |\n * | `gridTag` | `string`? | Grid tag label (default `\"A\"`) |\n */\nexport const PluginDesignCreateReferenceLinesArgs = z.object({\n profile: ProfileHandle,\n color: z.string().optional(),\n thickness: z.number().optional(),\n style: PluginReferenceLineStyle.optional(),\n gridTag: z.string().optional(),\n})\nexport type PluginDesignCreateReferenceLinesArgs = z.infer<\n typeof PluginDesignCreateReferenceLinesArgs\n>\n\n// ---------------------------------------------------------------------------\n// copy\n// ---------------------------------------------------------------------------\n\n/**\n * Copy mode for {@linkcode PluginDesignCreateApi.copy}.\n *\n * | Value | Description |\n * |---|---|\n * | `\"instance\"` | Keep copies in the source's instance family where possible |\n * | `\"unique\"` | Independent geometry copies |\n */\nexport const PluginCopyMode = z.enum([\"instance\", \"unique\"])\nexport type PluginCopyMode = z.infer<typeof PluginCopyMode>\n\n/**\n * Arguments for {@linkcode PluginDesignCreateApi.copy} (options flattened).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `components` | {@linkcode ComponentHandle}`[]` | Entities to copy (≥1) |\n * | `displacement` | {@linkcode Vec3Handle} | Per-copy offset (copy `i` at `displacement * i`) |\n * | `count` | `number`? | Copies per component (default 1) |\n * | `mode` | {@linkcode PluginCopyMode}? | `\"instance\"` (default) or `\"unique\"` |\n */\nexport const PluginDesignCreateCopyArgs = z.object({\n components: z.array(ComponentHandle).min(1),\n displacement: Vec3Handle,\n count: z.number().int().positive().optional(),\n mode: PluginCopyMode.optional(),\n})\nexport type PluginDesignCreateCopyArgs = z.infer<typeof PluginDesignCreateCopyArgs>\n// TRANSPORT: positional signature shipped —\n// copy(components: ComponentHandle[], displacement: Vec3Handle, options?: { count?, mode? })\n\n// ---------------------------------------------------------------------------\n// spaces (bulk)\n// ---------------------------------------------------------------------------\n\n/**\n * One space to create via {@linkcode PluginDesignCreateApi.spaces} — the same\n * footprint-extrude inputs as {@linkcode PluginDesignCreateApi.space}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `contour` | {@linkcode ContourHandle} | Footprint (outer profile + holes) |\n * | `height` | `number` | Extrude height |\n * | `label` | `string`? | Room label |\n * | `position` | {@linkcode Vec3Handle}? | Placement offset |\n * | `spaceType` | `PluginSpaceType`? | Space type |\n * | `massType` | `PluginMassType`? | Mass type |\n * | `departmentId` | `PluginDepartmentId`? | Department |\n */\nexport const PluginCreateSpaceItem = z.object({\n contour: ContourHandle,\n height: z.number(),\n label: z.string().optional(),\n position: Vec3Handle.optional(),\n spaceType: PluginSpaceType.optional(),\n massType: PluginMassType.optional(),\n departmentId: PluginDepartmentId.optional(),\n})\nexport type PluginCreateSpaceItem = z.infer<typeof PluginCreateSpaceItem>\n","// Space value types + schemas. The `entity.space.*` API was removed and its\n// operations migrated to `design.create.spaces` / `design.update.*` /\n// `design.query.*` / `design.delete.entities`. These shared space types survive\n// here because `design.create` / `design.query` / `design.update` import them.\nimport * as z from \"zod\"\nimport {\n ProfileHandle,\n Vec3Handle,\n Vec3Components,\n QuatComponents,\n CurveHandle,\n} from \"../../handles\"\n\n\n/**\n * Arguments for `createRectangular`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `position` | {@linkcode Vec3Handle} | Origin position in Babylon units |\n * | `dimensions` | `{ width, height, depth }` | Box dimensions in Babylon units |\n */\nexport const PluginSpaceCreateRectangularArgs = z.object({\n position: Vec3Handle,\n dimensions: z.object({\n width: z.number(),\n height: z.number(),\n depth: z.number(),\n }),\n})\n\nexport type PluginSpaceCreateRectangularArgs = z.infer<\n typeof PluginSpaceCreateRectangularArgs\n>\n\n/**\n * Result of `createRectangular`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | Unique ID of the created space |\n */\nexport const PluginSpaceCreateRectangularResult = z.object({\n spaceId: z.string(),\n})\n\nexport type PluginSpaceCreateRectangularResult = z.infer<\n typeof PluginSpaceCreateRectangularResult\n>\n\n/**\n * Arguments for `createFromProfile`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | Handle to a closed 2D profile (the outer floor shape) |\n * | `innerProfiles` | {@linkcode ProfileHandle}`[]` | Optional profile handles to subtract as holes |\n * | `extrudeHeight` | `number` | Extrusion height in Babylon units |\n * | `position` | {@linkcode Vec3Handle} | Offset position in Babylon units |\n */\nexport const PluginSpaceCreateFromProfileArgs = z.object({\n profile: ProfileHandle,\n innerProfiles: z.array(ProfileHandle).optional(),\n extrudeHeight: z.number(),\n position: Vec3Handle,\n})\n\nexport type PluginSpaceCreateFromProfileArgs = z.infer<\n typeof PluginSpaceCreateFromProfileArgs\n>\n\n/**\n * Result of `createFromProfile`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | Unique ID of the created space |\n */\nexport const PluginSpaceCreateFromProfileResult = z.object({\n spaceId: z.string(),\n})\n\nexport type PluginSpaceCreateFromProfileResult = z.infer<\n typeof PluginSpaceCreateFromProfileResult\n>\n\n/**\n * Arguments for `updateGeometryFromProfile`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | Space to update |\n * | `profile` | {@linkcode ProfileHandle} | Handle to the closed 2D profile defining the new floor shape |\n * | `extrudeHeight` | `number` | New extrusion height in Babylon units |\n */\nexport const PluginSpaceUpdateGeometryFromProfileArgs = z.object({\n spaceId: z.string(),\n profile: ProfileHandle,\n extrudeHeight: z.number(),\n})\n\nexport type PluginSpaceUpdateGeometryFromProfileArgs = z.infer<\n typeof PluginSpaceUpdateGeometryFromProfileArgs\n>\n\n/**\n * Result of `updateGeometryFromProfile`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | Unique ID of the updated space |\n */\nexport const PluginSpaceUpdateGeometryFromProfileResult = z.object({\n spaceId: z.string(),\n})\n\nexport type PluginSpaceUpdateGeometryFromProfileResult = z.infer<\n typeof PluginSpaceUpdateGeometryFromProfileResult\n>\n\n/**\n * Available properties that can be queried on a space.\n *\n * **Basic:**\n * | Value | Return Type | Description |\n * |---|---|---|\n * | `\"id\"` | `string` | Unique space identifier |\n * | `\"type\"` | `string` | Component type |\n * | `\"room_type\"` | `string` | Room type classification |\n * | `\"name\"` | `string` | Display name of the space |\n *\n * **Derived from parametric data:**\n * | Value | Return Type | Description |\n * |---|---|---|\n * | `\"area\"` | `number` | Bottom face area (from `areas_bottomFace`) |\n * | `\"breadth\"` | `number` | Breadth dimension |\n * | `\"depth\"` | `number` | Depth dimension |\n * | `\"height\"` | `number` | Height dimension |\n * | `\"massType\"` | `string \\| null` | Mass type classification |\n * | `\"spaceType\"` | `string \\| null` | Space type classification (Room, Balcony, etc.) |\n * | `\"storey\"` | `number \\| null` | Story the space belongs to |\n * | `\"departmentId\"` | `string \\| null` | Assigned department ID |\n * | `\"departmentName\"` | `string` | Assigned department name |\n * | `\"departmentColor\"` | `string` | Assigned department color (hex/CSS) |\n *\n * **Derived from mesh:**\n * | Value | Return Type | Description |\n * |---|---|---|\n * | `\"position\"` | {@linkcode Vec3Components} | Local position relative to parent |\n * | `\"absolutePosition\"` | {@linkcode Vec3Components} | Absolute position in the scene |\n * | `\"rotation\"` | {@linkcode Vec3Components} | Euler rotation angles (radians) |\n * | `\"rotationQuaternion\"` | {@linkcode QuatComponents} \\| `null` | Quaternion rotation, or `null` if unset |\n *\n * **Derived from brep:**\n * | Value | Return Type | Description |\n * |---|---|---|\n * | `\"planPoints\"` | {@linkcode Vec3Components}`[]` | Bottom outer profile points in world space with `y = 0` (2D plan). No closing duplicate point. |\n * | `\"profile\"` | {@linkcode CurveHandle}`[]` | Bottom outer profile curves in world space, as opaque curve handles. Read coordinates via the `core.geom.curve` read API. |\n * | `\"innerProfiles\"` | {@linkcode CurveHandle}`[][]` | Inner (hole) profile curve loops in world space — one loop per hole, `[]` when the space has none. Each curve is an opaque handle. |\n * | `\"innerPlanPoints\"` | {@linkcode Vec3Components}`[][]` | Inner (hole) profile points in world space with `y = 0` — one loop per hole, no closing duplicate, `[]` when none. |\n *\n * **Derived from adjacency manager:**\n * | Value | Return Type | Description |\n * |---|---|---|\n * | `\"adjacency\"` | `{ spaceId: string; value: number }[]` | Adjacency relationships to other spaces. `value`: `2` = Direct (required), `1` = Indirect or physical contact, `-1` = Restricted; `0` (no relationship) entries are filtered out. Empty when adjacency has never been computed — see `program.adjacency.compute`. |\n */\nexport const PluginSpaceGetProperty = z.enum([\n // Basic\n \"id\",\n \"type\",\n \"room_type\",\n \"name\",\n // Derived from parametric data\n \"area\",\n \"breadth\",\n \"depth\",\n \"height\",\n \"massType\",\n \"spaceType\",\n \"areaClass\",\n \"storey\",\n \"departmentId\",\n \"departmentName\",\n \"departmentColor\",\n // Derived from mesh\n \"position\",\n \"absolutePosition\",\n \"rotation\",\n \"rotationQuaternion\",\n // Derived from brep\n \"planPoints\",\n \"profile\",\n \"innerProfiles\",\n \"innerPlanPoints\",\n // Derived from adjacency manager\n \"adjacency\",\n])\n\n/**\n * Arguments for `get`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | The space ID to query |\n * | `properties` | {@linkcode PluginSpaceGetProperty}`[]` | Properties to retrieve |\n */\nexport const PluginSpaceGetArgs = z.object({\n spaceId: z.string(),\n properties: z.array(PluginSpaceGetProperty),\n})\n\nexport type PluginSpaceGetArgs = z.infer<typeof PluginSpaceGetArgs>\n\n/**\n * Supported space type values.\n *\n * Mirrors the internal `SpaceType` enum from `spaceType.types.ts`.\n *\n * | Value | Description |\n * |---|---|\n * | `\"Room\"` | Standard room |\n * | `\"Program Block\"` | Program/department block |\n * | `\"Balcony\"` | Balcony space |\n * | `\"Road\"` | Road |\n * | `\"Garden\"` | Garden area |\n * | `\"Deck\"` | Deck |\n * | `\"Pool\"` | Pool |\n * | `\"Walkway\"` | Walkway |\n * | `\"Envelope\"` | Envelope |\n * | `\"Parking\"` | Parking area |\n */\nexport const PluginSpaceType = z.enum([\n \"Room\",\n \"Program Block\",\n \"Balcony\",\n \"Road\",\n \"Garden\",\n \"Deck\",\n \"Pool\",\n \"Walkway\",\n \"Envelope\",\n \"Parking\",\n])\n/** The space-type value union (same-name type alias for positional signatures). */\nexport type PluginSpaceType = z.infer<typeof PluginSpaceType>\n\n/**\n * Area-class classification of a space (mirrors the internal `AreaClass` enum).\n *\n * | Value | Description |\n * |---|---|\n * | `\"NET\"` | Net (usable) area |\n * | `\"GROSS\"` | Gross area |\n * | `\"EXCLUDED\"` | Excluded from area totals |\n */\nexport const PluginAreaClass = z.enum([\"NET\", \"GROSS\", \"EXCLUDED\"])\n\n/**\n * Result of `get`.\n *\n * A partial object — only the properties that were requested in\n * {@linkcode PluginSpaceGetArgs.properties} will be present.\n */\nexport const PluginSpaceGetResult = z\n .object({\n // Basic\n id: z.string(),\n type: z.string(),\n room_type: z.string(),\n name: z.string(),\n // Derived from parametric data\n area: z.number(),\n breadth: z.number(),\n depth: z.number(),\n height: z.number(),\n massType: z.string().nullable(),\n spaceType: PluginSpaceType.nullable(),\n areaClass: PluginAreaClass,\n storey: z.number().nullable(),\n departmentId: z.string().nullable(),\n departmentName: z.string(),\n departmentColor: z.string(),\n // Derived from mesh\n position: Vec3Components,\n absolutePosition: Vec3Components,\n rotation: Vec3Components,\n rotationQuaternion: QuatComponents.nullable(),\n // Derived from brep\n planPoints: z.array(Vec3Components),\n profile: z.array(CurveHandle),\n innerProfiles: z.array(z.array(CurveHandle)),\n innerPlanPoints: z.array(z.array(Vec3Components)),\n // Derived from adjacency manager.\n // value: 2 = Direct (required), 1 = Indirect or physical contact, -1 = Restricted;\n // 0 (no relationship) entries are filtered out. Empty array when adjacency has\n // never been computed — run program.adjacency.compute() first for fresh data.\n adjacency: z.array(z.object({\n spaceId: z.string(),\n value: z.number(),\n })),\n })\n .partial()\n\nexport type PluginSpaceGetResult = z.infer<typeof PluginSpaceGetResult>\n\n/**\n * Result of `getAll`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spacesIds` | `string[]` | IDs of all spaces in the project |\n */\nexport const PluginSpaceGetAllResult = z.object({\n spacesIds: z.array(z.string()),\n})\n\nexport type PluginSpaceGetAllResult = z.infer<typeof PluginSpaceGetAllResult>\n\n/**\n * Arguments for `delete`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | The space ID to delete |\n */\nexport const PluginSpaceDeleteArgs = z.object({\n spaceId: z.string(),\n})\n\nexport type PluginSpaceDeleteArgs = z.infer<typeof PluginSpaceDeleteArgs>\n\n/** Result type for `delete` — returns nothing on success. */\nexport type PluginSpaceDeleteResult = void\n\n/**\n * Supported mass type values for {@linkcode PluginSpaceUpdateArgs.properties.massType}.\n *\n * Mirrors the internal `MASS_TYPES` enum.\n *\n * | Value | Description |\n * |---|---|\n * | `\"Plinth\"` | Plinth mass |\n * | `\"Void\"` | Void/cut-out |\n * | `\"Pergola\"` | Pergola structure |\n * | `\"Furniture\"` | Furniture element |\n * | `\"Facade element\"` | Facade element |\n * | `\"Generic mass\"` | Generic mass |\n * | `\"Room\"` | Room (default for spaces) |\n * | `\"Department\"` | Department block |\n * | `\"Building\"` | Building envelope |\n * | `\"Revit Import\"` | Imported from Revit |\n * | `\"Mass\"` | Generic mass type |\n * | `\"Site\"` | Site object |\n */\nexport const PluginMassType = z.enum([\n \"Plinth\",\n \"Void\",\n \"Pergola\",\n \"Furniture\",\n \"Facade element\",\n \"Generic mass\",\n \"Room\",\n \"Department\",\n \"Building\",\n \"Revit Import\",\n \"Mass\",\n \"Site\",\n])\n/** The mass-type value union (same-name type alias for positional signatures). */\nexport type PluginMassType = z.infer<typeof PluginMassType>\n\n/**\n * Well-known (built-in) department IDs.\n *\n * | Value | Department |\n * |---|---|\n * | `\"DEFAULT\"` | Default department |\n * | `\"SITE\"` | Site department |\n * | `\"ENVELOPE\"` | Envelope department |\n * | `\"CORE\"` | Core department |\n */\nexport const PluginWellKnownDepartmentId = z.enum([\n \"DEFAULT\",\n \"SITE\",\n \"ENVELOPE\",\n \"CORE\",\n])\n\n/**\n * Accepted department ID values — either a {@linkcode PluginWellKnownDepartmentId}\n * or a UUID string for custom (user-created) departments.\n */\nexport const PluginDepartmentId = z.union([\n PluginWellKnownDepartmentId,\n z.uuid(),\n])\n/** The department-id value union (same-name type alias for positional signatures). */\nexport type PluginDepartmentId = z.infer<typeof PluginDepartmentId>\n\n/**\n * Arguments for `update`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | The space ID to update |\n * | `properties` | `object` | Key/value pairs of properties to update (all optional) |\n * | `properties.room_type` | `string?` | New room type label |\n * | `properties.massType` | {@linkcode PluginMassType}`?` | New mass type |\n * | `properties.departmentId` | {@linkcode PluginDepartmentId}`?` | New department ID |\n */\nexport const PluginSpaceUpdateArgs = z.object({\n spaceId: z.string(),\n properties: z.object({\n room_type: z.string().optional(),\n massType: PluginMassType.optional(),\n spaceType: PluginSpaceType.optional(),\n areaClass: PluginAreaClass.optional(),\n departmentId: PluginDepartmentId.optional(),\n }),\n})\n\nexport type PluginSpaceUpdateArgs = z.infer<typeof PluginSpaceUpdateArgs>\n\n/**\n * Result of `update`.\n *\n * Echoes back the `spaceId` and the values of properties that were updated.\n * Properties that were not included in the update request will be `undefined`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | The space ID that was updated |\n * | `room_type` | `string?` | Updated room type (if changed) |\n * | `massType` | `string?` | Updated mass type (if changed) |\n * | `spaceType` | `string?` | Updated space type (if changed) |\n * | `departmentId` | `string \\| null?` | Updated department ID (if changed) |\n */\nexport const PluginSpaceUpdateResult = z.object({\n spaceId: z.string(),\n room_type: z.string().optional(),\n massType: z.string().optional(),\n spaceType: z.string().optional(),\n areaClass: PluginAreaClass.optional(),\n departmentId: z.string().nullable().optional(),\n})\n\nexport type PluginSpaceUpdateResult = z.infer<typeof PluginSpaceUpdateResult>\n\n// ---------------------------------------------------------------------------\n// Bulk operations\n// ---------------------------------------------------------------------------\n\n/**\n * A single item for `bulkCreate`.\n *\n * Discriminated on `kind`:\n * - `\"rectangular\"` — a box defined by `position` + `dimensions` (mirrors\n * {@linkcode PluginSpaceCreateRectangularArgs})\n * - `\"profile\"` — an extruded `profile` (with optional `innerProfiles`) by\n * `extrudeHeight` at `position` (mirrors {@linkcode PluginSpaceCreateFromProfileArgs})\n *\n * Every item may optionally set `room_type`, `spaceType`, `massType`, and\n * `departmentId`; these are applied within the same single undo step as the\n * creation.\n */\nexport const PluginSpaceBulkCreateItem = z.discriminatedUnion(\"kind\", [\n z.object({\n kind: z.literal(\"rectangular\"),\n position: Vec3Handle,\n dimensions: z.object({\n width: z.number(),\n height: z.number(),\n depth: z.number(),\n }),\n room_type: z.string().optional(),\n spaceType: PluginSpaceType.optional(),\n massType: PluginMassType.optional(),\n departmentId: PluginDepartmentId.optional(),\n }),\n z.object({\n kind: z.literal(\"profile\"),\n profile: ProfileHandle,\n innerProfiles: z.array(ProfileHandle).optional(),\n extrudeHeight: z.number(),\n position: Vec3Handle,\n room_type: z.string().optional(),\n spaceType: PluginSpaceType.optional(),\n massType: PluginMassType.optional(),\n departmentId: PluginDepartmentId.optional(),\n }),\n])\n\nexport type PluginSpaceBulkCreateItem = z.infer<typeof PluginSpaceBulkCreateItem>\n\n/**\n * Arguments for `bulkCreate`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `items` | {@linkcode PluginSpaceBulkCreateItem}`[]` | Spaces to create |\n */\nexport const PluginSpaceBulkCreateArgs = z.object({\n items: z.array(PluginSpaceBulkCreateItem),\n})\n\nexport type PluginSpaceBulkCreateArgs = z.infer<typeof PluginSpaceBulkCreateArgs>\n\n/**\n * Result of `bulkCreate`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceIds` | `string[]` | IDs of the created spaces, in input order |\n */\nexport const PluginSpaceBulkCreateResult = z.object({\n spaceIds: z.array(z.string()),\n})\n\nexport type PluginSpaceBulkCreateResult = z.infer<\n typeof PluginSpaceBulkCreateResult\n>\n\n/**\n * A single item for `bulkUpdate`.\n *\n * Targets an existing space by `spaceId`. Geometry fields `profile` and\n * `extrudeHeight` must be supplied **together** (mirrors\n * {@linkcode PluginSpaceUpdateGeometryFromProfileArgs}). Property changes are\n * nested under `properties`, mirroring {@linkcode PluginSpaceUpdateArgs}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceId` | `string` | The space to update |\n * | `profile` | {@linkcode ProfileHandle}`?` | New floor shape handle (requires `extrudeHeight`) |\n * | `extrudeHeight` | `number?` | New extrusion height (requires `profile`) |\n * | `properties` | `object?` | Property changes (same shape as {@linkcode PluginSpaceUpdateArgs.properties}) |\n */\nexport const PluginSpaceBulkUpdateItem = z.object({\n spaceId: z.string(),\n profile: ProfileHandle.optional(),\n extrudeHeight: z.number().optional(),\n properties: z\n .object({\n room_type: z.string().optional(),\n massType: PluginMassType.optional(),\n spaceType: PluginSpaceType.optional(),\n areaClass: PluginAreaClass.optional(),\n departmentId: PluginDepartmentId.optional(),\n })\n .optional(),\n})\n\nexport type PluginSpaceBulkUpdateItem = z.infer<typeof PluginSpaceBulkUpdateItem>\n\n/**\n * Arguments for `bulkUpdate`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `items` | {@linkcode PluginSpaceBulkUpdateItem}`[]` | Spaces to update |\n */\nexport const PluginSpaceBulkUpdateArgs = z.object({\n items: z.array(PluginSpaceBulkUpdateItem),\n})\n\nexport type PluginSpaceBulkUpdateArgs = z.infer<typeof PluginSpaceBulkUpdateArgs>\n\n/**\n * Result of `bulkUpdate`.\n *\n * Echoes one {@linkcode PluginSpaceUpdateResult} per item, in input order —\n * the same per-space shape returned by `update`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaces` | {@linkcode PluginSpaceUpdateResult}`[]` | Per-item updated values, in input order |\n */\nexport const PluginSpaceBulkUpdateResult = z.object({\n spaces: z.array(PluginSpaceUpdateResult),\n})\n\nexport type PluginSpaceBulkUpdateResult = z.infer<\n typeof PluginSpaceBulkUpdateResult\n>\n\n/**\n * Arguments for `bulkDelete`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceIds` | `string[]` | The space IDs to delete |\n */\nexport const PluginSpaceBulkDeleteArgs = z.object({\n spaceIds: z.array(z.string()),\n})\n\nexport type PluginSpaceBulkDeleteArgs = z.infer<typeof PluginSpaceBulkDeleteArgs>\n\n/**\n * Result of `bulkDelete`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `deletedSpaceIds` | `string[]` | The space IDs that were removed |\n */\nexport const PluginSpaceBulkDeleteResult = z.object({\n deletedSpaceIds: z.array(z.string()),\n})\n\nexport type PluginSpaceBulkDeleteResult = z.infer<\n typeof PluginSpaceBulkDeleteResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { ComponentHandle, BBoxComponents } from \"../../../handles\"\nimport {\n PluginSpaceType,\n PluginMassType,\n PluginDepartmentId,\n PluginAreaClass,\n} from \"../../entity/space\"\nimport { PluginDesignQueryGeometryApi } from \"./geometry\"\nimport { PluginDesignQuerySpacesApi } from \"./spaces\"\n\n// ---------------------------------------------------------------------------\n// Entity type vocabulary\n// ---------------------------------------------------------------------------\n\n/**\n * The kind of a BIM entity — the discovery/filter vocabulary for the whole\n * `design.query.*` surface. Values are clean `lowerCamel` tokens; the host maps\n * each to the engine's internal type (whose raw strings are case-inconsistent —\n * `\"roof\"`/`\"slab\"` lowercase, `\"Wall\"`/`\"Door\"` PascalCase — never surfaced here).\n *\n * | Value | Entity |\n * |---|---|\n * | `\"wall\"` | Wall |\n * | `\"space\"` | Space (a room mass) |\n * | `\"mass\"` | Generic mass (non-room) |\n * | `\"door\"` | Door |\n * | `\"window\"` | Window |\n * | `\"floor\"` | Floor |\n * | `\"slab\"` | Slab |\n * | `\"roof\"` | Roof |\n * | `\"column\"` | Column |\n * | `\"beam\"` | Beam |\n * | `\"ceiling\"` | Ceiling |\n * | `\"staircase\"` | Staircase |\n * | `\"furniture\"` | Furniture |\n * | `\"referenceLine\"` | Reference line |\n * | `\"curtainWall\"` | Parametric curtain wall |\n * | `\"mullion\"` | Curtain-wall mullion |\n * | `\"panel\"` | Curtain-wall panel |\n */\nexport const PluginEntityType = z.enum([\n \"wall\",\n \"space\",\n \"mass\",\n \"door\",\n \"window\",\n \"floor\",\n \"slab\",\n \"roof\",\n \"column\",\n \"beam\",\n \"ceiling\",\n \"staircase\",\n \"furniture\",\n \"referenceLine\",\n \"curtainWall\",\n \"mullion\",\n \"panel\",\n])\nexport type PluginEntityType = z.infer<typeof PluginEntityType>\n\n// ---------------------------------------------------------------------------\n// The shared filter — one options object, every list* method\n// ---------------------------------------------------------------------------\n\n/**\n * `EntityFilterOptions` — the **single filter** shared by every `design.query.list*`\n * method, so filtering is identical across all BIM object types. Every field is\n * optional and **AND-combined**: a component must satisfy all provided fields.\n * Plural fields are arrays (match any of); singular fields are scalars. A field\n * that names a type-specific dimension (`massTypes`/`spaceTypes`/`departmentId`)\n * excludes components that lack that dimension.\n *\n * | Field | Type | Keeps components where |\n * |---|---|---|\n * | `types` | {@linkcode PluginEntityType}`[]` | entity kind ∈ `types` (ignored by per-type `list*` — the method fixes the kind) |\n * | `storeys` | `number[]` | storey/floor level ∈ `storeys` (negative = basement) |\n * | `buildingIds` | `string[]` | building ∈ `buildingIds` |\n * | `structureIds` | `string[]` | structure ∈ `structureIds` |\n * | `label` | `string` | label (`room_type` ?? mesh label) === `label` |\n * | `massTypes` | {@linkcode PluginMassType}`[]` | mass-type ∈ (masses only) |\n * | `spaceTypes` | {@linkcode PluginSpaceType}`[]` | space-type ∈ (spaces only) |\n * | `departmentId` | {@linkcode PluginDepartmentId} | department === |\n * | `isSelected` | `boolean` | current selection state === |\n * | `isLocked` | `boolean` | lock flag === |\n * | `isHidden` | `boolean` | user-hidden flag === |\n * | `within` | {@linkcode BBoxComponents} | the entity's bounding box intersects the region |\n * | `overlaps` | {@linkcode ComponentHandle} | the entity's plan footprint overlaps the given space's bottom-face footprint — non-zero intersection area, so fully-inside, boundary-nested, and partially-overhanging entities all match; edge-touching with zero interior overlap does not. Exact polygon intersection (holes respected). Tested in plan — storey height is ignored; compose with `storeys` to scope a floor. Hidden entities are excluded by default — pass `isHidden` explicitly to override. The reference space itself is never returned. Throws on an unknown id. Entities without a brep footprint use their bounding-box plan rectangle. |\n * | `ids` | {@linkcode ComponentHandle}`[]` | id ∈ `ids` (restrict to a known set) |\n */\nexport const PluginEntityFilter = z.object({\n types: z.array(PluginEntityType).optional(),\n storeys: z.array(z.number()).optional(),\n buildingIds: z.array(z.string()).optional(),\n structureIds: z.array(z.string()).optional(),\n label: z.string().optional(),\n massTypes: z.array(PluginMassType).optional(),\n spaceTypes: z.array(PluginSpaceType).optional(),\n departmentId: PluginDepartmentId.optional(),\n isSelected: z.boolean().optional(),\n isLocked: z.boolean().optional(),\n isHidden: z.boolean().optional(),\n within: BBoxComponents.optional(),\n overlaps: ComponentHandle.optional(),\n ids: z.array(ComponentHandle).optional(),\n})\nexport type PluginEntityFilter = z.infer<typeof PluginEntityFilter>\n\n/**\n * Arguments for {@linkcode PluginDesignQueryApi.listByType} — a required entity\n * `type` plus every {@linkcode PluginEntityFilter} field.\n */\nexport const PluginDesignQueryListByTypeArgs = PluginEntityFilter.extend({\n type: PluginEntityType,\n})\nexport type PluginDesignQueryListByTypeArgs = z.infer<\n typeof PluginDesignQueryListByTypeArgs\n>\n\n// ---------------------------------------------------------------------------\n// Single-entity argument shapes\n// ---------------------------------------------------------------------------\n\n/** Arguments for methods that read one entity by its {@linkcode ComponentHandle}. */\nexport const PluginDesignQueryComponentArgs = z.object({\n component: ComponentHandle,\n})\nexport type PluginDesignQueryComponentArgs = z.infer<\n typeof PluginDesignQueryComponentArgs\n>\n\n/** Arguments for methods that look an entity up by id. */\nexport const PluginDesignQueryIdArgs = z.object({\n id: ComponentHandle,\n})\nexport type PluginDesignQueryIdArgs = z.infer<typeof PluginDesignQueryIdArgs>\n\n/** Arguments for methods over a set of entities (e.g. the union bounding box). */\nexport const PluginDesignQueryComponentsArgs = z.object({\n components: z.array(ComponentHandle),\n})\nexport type PluginDesignQueryComponentsArgs = z.infer<\n typeof PluginDesignQueryComponentsArgs\n>\n\n// ---------------------------------------------------------------------------\n// Read records\n// ---------------------------------------------------------------------------\n\n/**\n * The common property record returned by {@linkcode PluginDesignQueryApi.getProperties} —\n * a **partial** object (a field is present only when it applies to the entity).\n * Type-specific and geometry reads live on {@linkcode PluginDesignQueryApi.measure}\n * and `design.query.geometry.*`, keeping this record generic across every type.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | The entity id |\n * | `type` | {@linkcode PluginEntityType} | Entity kind |\n * | `label` | `string` | `room_type` ?? mesh label ?? `\"\"` |\n * | `storey` | `number` | Storey/floor level |\n * | `buildingId` | `string` | Owning building |\n * | `structureId` | `string` | Owning structure |\n * | `massType` | `string` | Mass-type (masses only) |\n * | `spaceType` | {@linkcode PluginSpaceType} | Space-type (spaces only) |\n * | `areaClass` | {@linkcode PluginAreaClass} | Area classification (spaces only) |\n * | `departmentId` | `string` | Department (masses only) |\n * | `isLocked` | `boolean` | Lock flag |\n * | `isHidden` | `boolean` | User-hidden flag |\n * | `isSelected` | `boolean` | Current selection state |\n * | `boundingBox` | {@linkcode BBoxComponents} | World-space AABB |\n * | `adjacency` | `{ spaceId: string; value: number }[]` | Adjacency relationships (spaces/masses only). `value`: `2` = Direct (required), `1` = Indirect or physical contact, `-1` = Restricted; `0` entries are filtered out. `[]` when adjacency has never been computed — see `program.adjacency.compute`. |\n */\nexport const PluginEntityProperties = z\n .object({\n id: z.string(),\n type: PluginEntityType,\n label: z.string(),\n storey: z.number(),\n buildingId: z.string(),\n structureId: z.string(),\n massType: z.string(),\n spaceType: PluginSpaceType,\n areaClass: PluginAreaClass,\n departmentId: z.string(),\n isLocked: z.boolean(),\n isHidden: z.boolean(),\n isSelected: z.boolean(),\n boundingBox: BBoxComponents,\n adjacency: z.array(z.object({ spaceId: z.string(), value: z.number() })),\n })\n .partial()\nexport type PluginEntityProperties = z.infer<typeof PluginEntityProperties>\n\n/**\n * The multi-metric bundle returned by {@linkcode PluginDesignQueryApi.measure}.\n * `boundingBox` is always present; the numeric metrics appear only when the\n * entity's type computes them (area: floors/masses/slabs/roofs/beams/columns;\n * volume: all; length: walls/beams).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `area` | `number`? | Bottom-face area |\n * | `volume` | `number`? | Solid volume |\n * | `length` | `number`? | Running length (linear elements) |\n * | `boundingBox` | {@linkcode BBoxComponents} | World-space AABB (always present) |\n */\nexport const PluginEntityMeasurements = z.object({\n area: z.number().optional(),\n volume: z.number().optional(),\n length: z.number().optional(),\n boundingBox: BBoxComponents,\n})\nexport type PluginEntityMeasurements = z.infer<typeof PluginEntityMeasurements>\n\n// ---------------------------------------------------------------------------\n// The query API\n// ---------------------------------------------------------------------------\n\n/**\n * `design.query.*` — read-only enumeration + inspection of scene-committed BIM\n * entities (all-handle model, §11). No query mutates the scene.\n *\n * Every `list*` returns a snapshot {@linkcode ComponentHandle}`[]` (`[]`, never\n * `null`) filtered by the shared {@linkcode PluginEntityFilter}; per-entity reads\n * take a {@linkcode ComponentHandle} and return primitive records / child handles\n * or `null` when the entity is gone. Resolve details of a returned handle with\n * {@linkcode PluginDesignQueryApi.getProperties} / {@linkcode PluginDesignQueryApi.measure}\n * / `design.query.geometry.*`.\n *\n * Accessed via `snaptrude.design.query`.\n */\nexport abstract class PluginDesignQueryApi {\n /** Entity-geometry reads (brep, bottom contour). See {@linkcode PluginDesignQueryGeometryApi}. */\n public abstract geometry: PluginDesignQueryGeometryApi\n /** Space-specific reads (footprint, …). See {@linkcode PluginDesignQuerySpacesApi}. */\n public abstract spaces: PluginDesignQuerySpacesApi\n\n constructor() {}\n\n // ── enumeration ───────────────────────────────────────────────────────────\n\n /**\n * List **all** BIM entities in the project matching the filter.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns matching entities as {@linkcode ComponentHandle}`[]` (`[]` if none)\n *\n * @examplePrompt Show me everything in the model\n * @examplePrompt How many objects are on the ground floor?\n * @examplePrompt List all the doors and windows on level 2\n * @examplePrompt What elements are currently selected?\n * @examplePrompt Find every hidden object in the project\n *\n * # Example\n * ```ts\n * // Doors and windows on the ground storey (fields AND-combine)\n * const doorsAndWindows = await snaptrude.design.query.listEntities({\n * types: [\"door\", \"window\"],\n * storeys: [1],\n * })\n *\n * // Everything the user currently has selected\n * const selected = await snaptrude.design.query.listEntities({ isSelected: true })\n *\n * // Everything inside a world-space region (axis-aligned box, Snaptrude units)\n * const inRegion = await snaptrude.design.query.listEntities({\n * within: { min: { x: 0, y: 0, z: 0 }, max: { x: 10, y: 4, z: 8 } },\n * })\n * ```\n */\n public abstract listEntities(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all entities of one BIM object type — wall, door, slab, panel, and so\n * on — optionally narrowed by the shared filter.\n *\n * @param type - the {@linkcode PluginEntityType} to list\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns matching entities as {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt List all the curtain walls in the project\n * @examplePrompt Show every curtain wall panel on this storey\n * @examplePrompt Get all the elements of a single type, like columns\n * @examplePrompt Find all the locked slabs in the model\n *\n * # Example\n * ```ts\n * const lockedSlabs = await snaptrude.design.query.listByType(\"slab\", { isLocked: true })\n *\n * // Curtain-wall panels on storeys 2-3 of one building\n * const panels = await snaptrude.design.query.listByType(\"panel\", {\n * storeys: [2, 3],\n * buildingIds: [\"bld_1\"],\n * })\n * ```\n */\n public abstract listByType(\n type: PluginEntityType,\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the walls in the project, optionally filtered by storey, building,\n * label, selection state, or region.\n *\n * The `types` field of the filter is ignored (this method fixes the kind).\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns wall {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt How many walls are in the project?\n * @examplePrompt List all the walls on the ground floor\n * @examplePrompt Which walls are currently selected?\n * @examplePrompt Find the walls on level 2 of building A\n * @examplePrompt Show me every hidden wall\n *\n * # Example\n * ```ts\n * const groundFloorWalls = await snaptrude.design.query.listWalls({ storeys: [1] })\n * ```\n */\n public abstract listWalls(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the spaces (rooms) in the project, optionally filtered by storey,\n * department, space type, label, selection state, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns space {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt How many rooms are in this project?\n * @examplePrompt List all the spaces on the second storey\n * @examplePrompt Which rooms are in the Bedrooms department?\n * @examplePrompt Find every room labelled Kitchen\n * @examplePrompt Show the spaces that are currently selected\n *\n * # Example\n * ```ts\n * // Balconies and decks on storey 2 (`label` is an exact match on room_type)\n * const outdoor = await snaptrude.design.query.listSpaces({\n * storeys: [2],\n * spaceTypes: [\"Balcony\", \"Deck\"],\n * })\n *\n * // Rooms in a department: resolve its id first, then filter and total the area\n * const { departments } = await snaptrude.program.departments.list()\n * const bedrooms = departments.find((d) => d.name === \"Bedrooms\")\n * if (bedrooms) {\n * const rooms = await snaptrude.design.query.listSpaces({ departmentId: bedrooms.id })\n * let total = 0\n * for (const room of rooms) {\n * const m = await snaptrude.design.query.measure(room)\n * total += m?.area ?? 0\n * }\n * }\n * ```\n */\n public abstract listSpaces(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the generic masses (non-room massing volumes) in the project,\n * optionally filtered by storey, building, label, mass type, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns mass {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt List all the masses in the model\n * @examplePrompt How many massing blocks are on the site?\n * @examplePrompt Show the generic masses on level 1\n * @examplePrompt Find every mass that isn't a room\n *\n * # Example\n * ```ts\n * // Only certain mass kinds — massTypes matches any of the given values\n * const massing = await snaptrude.design.query.listMasses({\n * massTypes: [\"Generic mass\", \"Plinth\"],\n * })\n * ```\n */\n public abstract listMasses(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the doors in the project, optionally filtered by storey, building,\n * selection state, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns door {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt How many doors are in the project?\n * @examplePrompt List all the doors on the ground floor\n * @examplePrompt Which doors are currently selected?\n * @examplePrompt Find every door in building B\n *\n * # Example\n * ```ts\n * // Ground-floor doors, then read each one's width via design.doors.*\n * const doors = await snaptrude.design.query.listDoors({ storeys: [1] })\n * for (const door of doors) {\n * const width = await snaptrude.design.doors.getWidth(door)\n * }\n * ```\n */\n public abstract listDoors(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the windows in the project, optionally filtered by storey,\n * building, selection state, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns window {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt How many windows does this building have?\n * @examplePrompt List every window on level 3\n * @examplePrompt Which windows are on the ground floor?\n * @examplePrompt Show all the windows that are currently selected\n *\n * # Example\n * ```ts\n * const level3Windows = await snaptrude.design.query.listWindows({ storeys: [3] })\n * ```\n */\n public abstract listWindows(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the floor elements (floor plates / finishes) in the project,\n * optionally filtered by storey, building, lock state, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns floor {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt List all the floor elements in the model\n * @examplePrompt How many floor plates are on the second storey?\n * @examplePrompt Which floors are locked?\n * @examplePrompt Show the floor finishes on level 0\n *\n * # Example\n * ```ts\n * const lockedFloors = await snaptrude.design.query.listFloors({ isLocked: true })\n * ```\n */\n public abstract listFloors(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the slabs in the project, optionally filtered by storey, building,\n * lock state, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns slab {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt List all the slabs in the project\n * @examplePrompt How many slabs are on level 2?\n * @examplePrompt Which slabs are locked?\n * @examplePrompt Show the slabs in the selected building\n *\n * # Example\n * ```ts\n * const storey2Slabs = await snaptrude.design.query.listSlabs({ storeys: [2] })\n * ```\n */\n public abstract listSlabs(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the roofs in the project, optionally filtered by storey, building,\n * visibility, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns roof {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt How many roofs does the model have?\n * @examplePrompt List all the roof elements\n * @examplePrompt Show the roofs on the top storey\n * @examplePrompt Find every hidden roof\n *\n * # Example\n * ```ts\n * const hiddenRoofs = await snaptrude.design.query.listRoofs({ isHidden: true })\n * ```\n */\n public abstract listRoofs(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the columns in the project, optionally filtered by storey,\n * building, selection state, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns column {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt How many columns are on the ground floor?\n * @examplePrompt List all the columns in building A\n * @examplePrompt Show every column on level 3\n * @examplePrompt Which columns are currently selected?\n *\n * # Example\n * ```ts\n * const groundFloorColumns = await snaptrude.design.query.listColumns({ storeys: [1] })\n * ```\n */\n public abstract listColumns(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the beams in the project, optionally filtered by storey, building,\n * lock state, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns beam {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt List all the beams in the project\n * @examplePrompt How many beams are on the second storey?\n * @examplePrompt Show the beams in this structure\n * @examplePrompt Find every locked beam\n *\n * # Example\n * ```ts\n * const storey2Beams = await snaptrude.design.query.listBeams({ storeys: [2] })\n * ```\n */\n public abstract listBeams(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the ceilings in the project, optionally filtered by storey,\n * building, visibility, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns ceiling {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt List all the ceilings in the model\n * @examplePrompt How many ceilings are on level 1?\n * @examplePrompt Which ceilings are hidden?\n * @examplePrompt Show the ceilings in building B\n *\n * # Example\n * ```ts\n * const hiddenCeilings = await snaptrude.design.query.listCeilings({ isHidden: true })\n * ```\n */\n public abstract listCeilings(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the staircases in the project, optionally filtered by storey,\n * building, selection state, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns staircase {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt How many staircases are in the building?\n * @examplePrompt List all the stairs in the project\n * @examplePrompt Show the staircases on the ground floor\n * @examplePrompt Which stairs are currently selected?\n *\n * # Example\n * ```ts\n * const groundFloorStairs = await snaptrude.design.query.listStaircases({ storeys: [1] })\n * ```\n */\n public abstract listStaircases(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the furniture in the project, optionally filtered by storey,\n * building, label, selection state, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns furniture {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt List all the furniture in the project\n * @examplePrompt How many furniture items are on this floor?\n * @examplePrompt Show the furniture inside the selected room\n * @examplePrompt Which furniture is on storey 2?\n *\n * # Example\n * ```ts\n * // Furniture whose plan footprint overlaps a room (`overlaps` is plan-only —\n * // scope the storey too, or furniture stacked on other floors matches)\n * const [kitchen] = await snaptrude.design.query.listSpaces({ label: \"Kitchen\" })\n * if (kitchen) {\n * const inKitchen = await snaptrude.design.query.listFurniture({\n * overlaps: kitchen,\n * storeys: [1],\n * })\n * }\n * ```\n */\n public abstract listFurniture(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the reference lines in the project, optionally filtered by storey,\n * building, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns reference-line {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt List all the reference lines in the model\n * @examplePrompt Show the guide lines on the ground floor\n * @examplePrompt How many reference lines are on this storey?\n * @examplePrompt Find the setting-out lines in building A\n *\n * # Example\n * ```ts\n * const groundFloorRefLines = await snaptrude.design.query.listReferenceLines({ storeys: [1] })\n * ```\n */\n public abstract listReferenceLines(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * List all the curtain-wall mullions in the project, optionally filtered by\n * storey, building, selection state, or region.\n *\n * @param filter - an optional {@linkcode PluginEntityFilter}\n * @returns mullion {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt List all the mullions in the curtain wall\n * @examplePrompt How many mullions are on the facade?\n * @examplePrompt Show every curtain wall mullion on level 5\n * @examplePrompt Which mullions are currently selected?\n *\n * # Example\n * ```ts\n * const level5Mullions = await snaptrude.design.query.listMullions({ storeys: [5] })\n * ```\n */\n public abstract listMullions(\n filter?: PluginEntityFilter,\n ): PluginApiReturn<ComponentHandle[]>\n\n // ── single-entity access & identity ─────────────────────────────────────────\n\n /**\n * Look an entity up by id — returns the same handle if it still resolves live,\n * else `null`. A cheap validity probe (distinct from {@linkcode PluginDesignQueryApi.exists}).\n *\n * @param id - the entity id ({@linkcode ComponentHandle}) to look up\n * @returns the {@linkcode ComponentHandle}, or `null` if it no longer resolves\n *\n * @examplePrompt Look up an object by its id\n * @examplePrompt Does id cmp_42 still point to something in the model?\n * @examplePrompt Fetch the element with this id\n * @examplePrompt Check if this saved element id is still valid\n *\n * # Example\n * ```ts\n * // Persistence round-trip: save a ref now, revalidate it in a later run\n * const [wall] = await snaptrude.design.query.listWalls()\n * const savedRef = await snaptrude.design.query.getEntityRef(wall)\n *\n * // ...later (savedRef restored from plugin storage)...\n * const stillThere = await snaptrude.design.query.getById(savedRef)\n * if (stillThere) {\n * const props = await snaptrude.design.query.getProperties(stillThere)\n * }\n * ```\n */\n public abstract getById(\n id: ComponentHandle,\n ): PluginApiReturn<ComponentHandle | null>\n\n /**\n * Test whether an entity id resolves to a live scene entity.\n * @param id - the entity id ({@linkcode ComponentHandle}) to look up\n * @returns `true` if it exists, otherwise `false`\n *\n * @examplePrompt Does this element still exist in the scene?\n * @examplePrompt Check whether the wall I stored earlier is still there\n * @examplePrompt Is id cmp_42 still valid?\n * @examplePrompt Verify the object wasn't deleted\n *\n * # Example\n * ```ts\n * // Guard before acting on a handle that may have been deleted or undone\n * if (await snaptrude.design.query.exists(wall)) {\n * const dx = await snaptrude.core.math.vec3.new(5, 0, 0)\n * await snaptrude.design.transform.move([wall], dx)\n * }\n * ```\n */\n public abstract exists(\n id: ComponentHandle,\n ): PluginApiReturn<boolean>\n\n /**\n * Get the kind of BIM entity a handle refers to — wall, door, space, slab,\n * and so on (its {@linkcode PluginEntityType}).\n * @param component - the entity's {@linkcode ComponentHandle}\n * @returns the kind, or `null` if the entity is gone / its type is unknown\n *\n * @examplePrompt What kind of element is this?\n * @examplePrompt Is the selected object a wall or a mass?\n * @examplePrompt Tell me the type of this component\n * @examplePrompt What am I looking at — a door, a window, or a panel?\n *\n * # Example\n * ```ts\n * // Dispatch on what the user selected\n * const selection = await snaptrude.design.selection.get()\n * for (const component of selection) {\n * const kind = await snaptrude.design.query.getEntityType(component)\n * if (kind === \"wall\") {\n * // wall-specific handling\n * } else if (kind === \"space\") {\n * // room-specific handling\n * }\n * }\n * ```\n */\n public abstract getEntityType(\n component: ComponentHandle,\n ): PluginApiReturn<PluginEntityType | null>\n\n /**\n * Get an entity's human label (`room_type` for spaces/masses, else the mesh\n * label; `\"\"` when unlabelled). The write side is `design.update` (`setLabel`).\n * @param component - the entity's {@linkcode ComponentHandle}\n * @returns the label string\n *\n * @examplePrompt What is this room called?\n * @examplePrompt Get the name of the selected object\n * @examplePrompt Show the label on this wall\n * @examplePrompt What's the room type of this space?\n *\n * # Example\n * ```ts\n * // Fuzzy label search (the `label` filter field is exact-match; for\n * // case-insensitive or partial matches, read labels and compare yourself)\n * const spaces = await snaptrude.design.query.listSpaces()\n * const kitchens: typeof spaces = []\n * for (const space of spaces) {\n * const label = await snaptrude.design.query.getLabel(space)\n * if (label.toLowerCase().includes(\"kitchen\")) kitchens.push(space)\n * }\n * ```\n */\n public abstract getLabel(\n component: ComponentHandle,\n ): PluginApiReturn<string>\n\n /**\n * Get a serializable, persistable reference to an entity. Under the all-handle\n * model a {@linkcode ComponentHandle} already IS the ref (raw `Component.id`),\n * so this is the identity passthrough — provided for API completeness.\n * @param component - the entity's {@linkcode ComponentHandle}\n * @returns the entity's {@linkcode ComponentHandle}\n *\n * @examplePrompt Give me a reference I can save for this element\n * @examplePrompt Get a persistent id for the selected wall\n * @examplePrompt Store a handle to this room so I can find it later\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const savedRef = await snaptrude.design.query.getEntityRef(wall)\n * // savedRef is a plain string — persist it, then revalidate in a later run\n * // with snaptrude.design.query.getById(savedRef)\n * ```\n */\n public abstract getEntityRef(\n component: ComponentHandle,\n ): PluginApiReturn<ComponentHandle>\n\n /**\n * List an entity's direct child entities — for example the doors and windows\n * hosted in a wall.\n * @param component - the entity's {@linkcode ComponentHandle}\n * @returns child {@linkcode ComponentHandle}`[]` (`[]` if none)\n *\n * @examplePrompt What's inside this wall — list its doors and windows\n * @examplePrompt Show the child elements of the selected object\n * @examplePrompt Which openings belong to this wall?\n * @examplePrompt List everything nested under this mass\n *\n * # Example\n * ```ts\n * // Count the openings hosted in a wall, split by kind\n * const children = await snaptrude.design.query.listChildren(wall)\n * let doors = 0\n * let windows = 0\n * for (const child of children) {\n * const kind = await snaptrude.design.query.getEntityType(child)\n * if (kind === \"door\") doors++\n * if (kind === \"window\") windows++\n * }\n * ```\n */\n public abstract listChildren(\n component: ComponentHandle,\n ): PluginApiReturn<ComponentHandle[]>\n\n /**\n * Get an entity's host/parent entity (e.g. the wall a door is cut into).\n * @param component - the entity's {@linkcode ComponentHandle}\n * @returns the host {@linkcode ComponentHandle}, or `null` if top-level\n *\n * @examplePrompt Which wall is this door in?\n * @examplePrompt Find the parent of the selected window\n * @examplePrompt What is this element attached to?\n * @examplePrompt Which wall hosts this window?\n *\n * # Example\n * ```ts\n * // From a door up to its host wall, then measure the wall\n * const [door] = await snaptrude.design.query.listDoors({ isSelected: true })\n * const hostWall = door ? await snaptrude.design.query.getHost(door) : null\n * if (hostWall) {\n * const m = await snaptrude.design.query.measure(hostWall)\n * console.log(\"wall length:\", m?.length)\n * }\n * ```\n */\n public abstract getHost(\n component: ComponentHandle,\n ): PluginApiReturn<ComponentHandle | null>\n\n // ── property & metric reads ─────────────────────────────────────────────────\n\n /**\n * Read an entity's common properties as a {@linkcode PluginEntityProperties}\n * record (only applicable fields are present). For spaces/masses this includes\n * `adjacency` — the per-entity adjacency read (bulk form:\n * `program.adjacency.getMatrix`).\n *\n * @param component - the entity's {@linkcode ComponentHandle}\n * @returns the property record\n *\n * @examplePrompt Show me all the details of the selected object\n * @examplePrompt What storey is this wall on?\n * @examplePrompt Which department does this room belong to?\n * @examplePrompt Is this element locked or hidden?\n * @examplePrompt Get the adjacencies of this space\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const props = await snaptrude.design.query.getProperties(wall)\n * console.log(props.type, props.storey, props.boundingBox)\n *\n * // The record is partial — type-specific fields exist only where they apply\n * const [room] = await snaptrude.design.query.listSpaces()\n * const p = await snaptrude.design.query.getProperties(room)\n * if (p.spaceType === \"Room\" && p.areaClass === \"NET\") {\n * for (const adj of p.adjacency ?? []) {\n * // adj.value: 2 = direct, 1 = indirect/contact, -1 = restricted\n * console.log(adj.spaceId, adj.value)\n * }\n * }\n * ```\n */\n public abstract getProperties(\n component: ComponentHandle,\n ): PluginApiReturn<PluginEntityProperties>\n\n /**\n * Measure an entity — read its area, volume, and/or running length (whichever\n * its type supports) together with its world-space bounding box in one call.\n *\n * @param component - the entity's {@linkcode ComponentHandle}\n * @returns a {@linkcode PluginEntityMeasurements}, or `null` if the entity is gone\n *\n * @examplePrompt What's the area of this room?\n * @examplePrompt How long is the selected wall?\n * @examplePrompt Get the volume of this mass\n * @examplePrompt Give me the dimensions of the selected element\n * @examplePrompt What's the floor area of the kitchen?\n *\n * # Example\n * ```ts\n * const [space] = await snaptrude.design.query.listSpaces()\n * const m = await snaptrude.design.query.measure(space)\n * console.log(m?.area, m?.volume)\n * ```\n */\n public abstract measure(\n component: ComponentHandle,\n ): PluginApiReturn<PluginEntityMeasurements | null>\n\n /**\n * Get the **union** axis-aligned bounding box enclosing a set of entities.\n *\n * @param components - the set of entity {@linkcode ComponentHandle}s\n * @returns the union {@linkcode BBoxComponents}, or `null` if the set is empty /\n * none resolve\n *\n * @examplePrompt Get the bounding box around the selected objects\n * @examplePrompt What is the overall extent of these walls?\n * @examplePrompt How big is the region these elements cover together?\n * @examplePrompt Find the combined extents of everything on level 2\n *\n * # Example\n * ```ts\n * const walls = await snaptrude.design.query.listWalls()\n * const box = await snaptrude.design.query.getBoundingBox(walls)\n *\n * // Compose with the `within` filter: everything in the selection's extents\n * const selection = await snaptrude.design.selection.get()\n * const extents = await snaptrude.design.query.getBoundingBox(selection)\n * if (extents) {\n * const nearby = await snaptrude.design.query.listEntities({ within: extents })\n * const width = extents.max.x - extents.min.x\n * }\n * ```\n */\n public abstract getBoundingBox(\n components: ComponentHandle[],\n ): PluginApiReturn<BBoxComponents | null>\n}\n\nexport * from \"./geometry\"\nexport * from \"./spaces\"\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../../types\"\nimport {\n ComponentHandle,\n BrepHandle,\n ContourHandle,\n CurveHandle,\n} from \"../../../../handles\"\n\n/**\n * `snaptrude.design.query.geometry` — read the geometry of scene BIM entities.\n *\n * This is the bridge from the BIM/scene layer (`design.*`, keyed by\n * {@linkcode ComponentHandle}) into the geometry kernel (`core.geom.query.*`,\n * keyed by value/topology handles). {@linkcode PluginDesignQueryGeometryApi.getBrep}\n * mints a {@linkcode BrepHandle} for a component's boundary-representation mesh;\n * {@linkcode PluginDesignQueryGeometryApi.getBottomContour} mints a\n * {@linkcode ContourHandle} for its footprint outline;\n * {@linkcode PluginDesignQueryGeometryApi.getCenterline} mints a\n * {@linkcode CurveHandle} for a wall's core curve.\n *\n * Returned handles are session-ephemeral and go stale on undo/redo/re-topologize\n * — re-fetch a fresh one after edits.\n */\nexport abstract class PluginDesignQueryGeometryApi {\n constructor() {}\n\n /**\n * Get the boundary representation (B-rep) of a scene component — the solid\n * geometry (faces, edges, vertices) behind a wall, slab, room or any other\n * scene entity, as a reusable {@linkcode BrepHandle} for the\n * `core.geom.query.brep.*` reads.\n *\n * @param component - The scene component to read\n * @returns The brep as a {@linkcode BrepHandle}, or `null` if the component has no brep geometry\n *\n * @examplePrompt Get the 3D solid geometry of the selected wall\n * @examplePrompt How many faces does this mass have?\n * @examplePrompt Inspect the mesh of this slab so I can look at its faces and edges\n * @examplePrompt Read the vertices of the selected column's geometry\n *\n * @example\n * ```ts\n * const brep = await snaptrude.design.query.geometry.getBrep(component)\n * if (brep) {\n * const faces = await snaptrude.core.geom.query.brep.listFaces(brep)\n * }\n * ```\n */\n public abstract getBrep(\n component: ComponentHandle\n ): PluginApiReturn<BrepHandle | null>\n\n /**\n * Get the **bottom-face contour** of a component — the footprint outline (outer\n * profile + holes) of its lowest horizontal face, as a reusable\n * {@linkcode ContourHandle}.\n *\n * Extracted from the component's B-rep; robust to inverted face normals. Read\n * its geometry via `snaptrude.core.geom.query.contour.*`, or feed it back into\n * `design.create.*` / `core.geom.*`.\n *\n * @param component - The scene component to read\n * @returns the footprint {@linkcode ContourHandle}, or `null` if the component\n * has no extractable bottom face (e.g. it carries no B-rep)\n *\n * @examplePrompt Get the footprint of the selected mass\n * @examplePrompt What is the plan outline of this building volume?\n * @examplePrompt Trace the base profile of this wall\n * @examplePrompt Find the ground-level outline of the slab, including any openings\n * @examplePrompt Work out the footprint area of the selected component\n *\n * @example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const contour = await snaptrude.design.query.geometry.getBottomContour(wall)\n * if (contour) {\n * const area = await snaptrude.core.geom.query.contour.getArea(contour)\n * }\n * ```\n */\n public abstract getBottomContour(\n component: ComponentHandle\n ): PluginApiReturn<ContourHandle | null>\n\n /**\n * Get the **centerline** (core curve) of a wall — the single curve running\n * down the middle of the wall, as a reusable {@linkcode CurveHandle}\n * (a `Line` for a straight wall, an `Arc` for a curved wall).\n *\n * For a parametric wall this is its stored core curve; otherwise it is\n * derived from the wall's B-rep bottom face. Read its geometry via\n * `snaptrude.core.geom.query.curve.*`, or feed it into `design.create.*`.\n *\n * Only walls have a centerline. As with all `get*` reads it never throws:\n * a non-wall component, or a wall with no derivable centerline, yields `null`.\n *\n * @param component - The scene component to read (only walls yield a centerline)\n * @returns the centerline {@linkcode CurveHandle}, or `null` if the component\n * is not a wall or the wall has no derivable centerline (e.g. it carries no\n * B-rep or has an unsupported profile)\n *\n * @examplePrompt Get the centerline of the selected wall\n * @examplePrompt How long is this wall along its centre line?\n * @examplePrompt Find the axis running down the middle of this wall\n * @examplePrompt Give me the core curve of that curved wall\n * @examplePrompt Where does the wall's centreline start and end?\n *\n * @example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const centerline = await snaptrude.design.query.geometry.getCenterline(wall)\n * if (centerline) {\n * const length = await snaptrude.core.geom.query.curve.getLength(centerline)\n * }\n * ```\n */\n public abstract getCenterline(\n component: ComponentHandle\n ): PluginApiReturn<CurveHandle | null>\n}\n\n/**\n * Arguments for {@linkcode PluginDesignQueryGeometryApi.getBrep}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `component` | {@linkcode ComponentHandle} | The scene component to read |\n */\nexport const PluginDesignQueryGeometryGetBrepArgs = z.object({\n component: ComponentHandle,\n})\n\nexport type PluginDesignQueryGeometryGetBrepArgs = z.infer<\n typeof PluginDesignQueryGeometryGetBrepArgs\n>\n\n/**\n * Arguments for {@linkcode PluginDesignQueryGeometryApi.getBottomContour}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `component` | {@linkcode ComponentHandle} | The scene component to read |\n */\nexport const PluginDesignQueryGeometryGetBottomContourArgs = z.object({\n component: ComponentHandle,\n})\n\nexport type PluginDesignQueryGeometryGetBottomContourArgs = z.infer<\n typeof PluginDesignQueryGeometryGetBottomContourArgs\n>\n\n/**\n * Arguments for {@linkcode PluginDesignQueryGeometryApi.getCenterline}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `component` | {@linkcode ComponentHandle} | The scene component to read |\n */\nexport const PluginDesignQueryGeometryGetCenterlineArgs = z.object({\n component: ComponentHandle,\n})\n\nexport type PluginDesignQueryGeometryGetCenterlineArgs = z.infer<\n typeof PluginDesignQueryGeometryGetCenterlineArgs\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { ComponentHandle, ContourHandle } from \"../../../handles\"\nimport { PluginSpaceGetProperty, PluginSpaceGetResult } from \"../../entity/space\"\n\n/**\n * `design.query.spaces.*` — space-specific reads (a space is a room mass).\n *\n * Only the space queries feasible against the engine today are exposed here.\n * `getFloor` / `listBoundingWalls` (space↔wall topology) are deferred — they need\n * engine work that does not exist yet. `listAdjacent` stays deferred because the\n * shipped surfaces already answer it with value semantics: per-space via the\n * `adjacency` field of `design.query.getProperties`, in bulk via\n * `program.adjacency.getMatrix`.\n *\n * Accessed via `snaptrude.design.query.spaces`.\n */\nexport abstract class PluginDesignQuerySpacesApi {\n constructor() {}\n\n /**\n * Get selected properties of a space — the selective multi-property read.\n *\n * Only the properties listed in `properties` are returned — unlisted\n * properties will be `undefined` in the result. This is the canonical home of\n * the read formerly at `entity.space.get` (now deprecated). Adjacency is not\n * part of this read — it is an entity property: read it via the `adjacency`\n * field of {@linkcode PluginDesignQueryApi.getProperties}.\n *\n * @param space - The space (room mass) to read\n * @param properties - Array of property names to retrieve. See\n * {@linkcode PluginDesignQuerySpacesGetProperty} for available values.\n * @returns A partial {@linkcode PluginDesignQuerySpacesGetResult} containing only\n * the requested properties\n * @throws If the space does not exist or the component is not a space/mass\n *\n * @examplePrompt What is the area of this room?\n * @examplePrompt Get the name, storey and height of the selected space\n * @examplePrompt Which department does this room belong to?\n * @examplePrompt Where is this space positioned on the plan?\n * @examplePrompt Read the room type and dimensions of the selected room\n *\n * # Example\n * ```ts\n * const [space] = await snaptrude.design.query.listSpaces()\n * const info = await snaptrude.design.query.spaces.get(space, [\"name\", \"area\", \"position\"])\n * console.log(info.name, info.area, info.position)\n * ```\n */\n public abstract get(\n space: ComponentHandle,\n properties: PluginDesignQuerySpacesGetArgs[\"properties\"],\n ): PluginApiReturn<PluginDesignQuerySpacesGetResult>\n\n /**\n * Get the **footprint** of a space — its bottom-face contour (outer profile +\n * holes) as a reusable {@linkcode ContourHandle}. Equivalent to\n * {@linkcode PluginDesignQueryGeometryApi.getBottomContour} narrowed to spaces.\n *\n * @param space - The space (room mass) to read\n * @returns the footprint {@linkcode ContourHandle}, or `null` if the space has\n * no extractable footprint\n *\n * @examplePrompt Get the footprint of this room\n * @examplePrompt Trace the floor outline of the selected space\n * @examplePrompt What is the plan boundary of this room, including any holes?\n * @examplePrompt Give me the base profile of the selected room mass\n *\n * # Example\n * ```ts\n * const [space] = await snaptrude.design.query.listSpaces()\n * const footprint = await snaptrude.design.query.spaces.getFootprint(space)\n * ```\n */\n public abstract getFootprint(\n space: ComponentHandle,\n ): PluginApiReturn<ContourHandle | null>\n}\n\n/**\n * Arguments for {@linkcode PluginDesignQuerySpacesApi.getFootprint}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `space` | {@linkcode ComponentHandle} | The space (room mass) to read |\n */\nexport const PluginDesignQueryGetFootprintArgs = z.object({\n space: ComponentHandle,\n})\nexport type PluginDesignQueryGetFootprintArgs = z.infer<\n typeof PluginDesignQueryGetFootprintArgs\n>\n\n/**\n * Property names readable via {@linkcode PluginDesignQuerySpacesApi.get} — the\n * legacy {@linkcode PluginSpaceGetProperty} set minus `\"adjacency\"` (adjacency is\n * an entity property: see the `adjacency` field of\n * {@linkcode PluginDesignQueryApi.getProperties}).\n */\nexport const PluginDesignQuerySpacesGetProperty =\n PluginSpaceGetProperty.exclude([\"adjacency\"])\nexport type PluginDesignQuerySpacesGetProperty = z.infer<\n typeof PluginDesignQuerySpacesGetProperty\n>\n\n/**\n * Arguments for {@linkcode PluginDesignQuerySpacesApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `space` | {@linkcode ComponentHandle} | The space (room mass) to read |\n * | `properties` | {@linkcode PluginDesignQuerySpacesGetProperty}`[]` | Properties to retrieve |\n */\nexport const PluginDesignQuerySpacesGetArgs = z.object({\n space: ComponentHandle,\n properties: z.array(PluginDesignQuerySpacesGetProperty),\n})\nexport type PluginDesignQuerySpacesGetArgs = z.infer<\n typeof PluginDesignQuerySpacesGetArgs\n>\n\n/**\n * Result of {@linkcode PluginDesignQuerySpacesApi.get} — the legacy\n * {@linkcode PluginSpaceGetResult} record minus `adjacency`. Partial: only the\n * requested properties are present.\n */\nexport const PluginDesignQuerySpacesGetResult = PluginSpaceGetResult.omit({\n adjacency: true,\n})\nexport type PluginDesignQuerySpacesGetResult = z.infer<\n typeof PluginDesignQuerySpacesGetResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { ComponentHandle } from \"../../../handles\"\nimport { PluginDesignChangeResult } from \"../lock\"\n\n/**\n * `snaptrude.design.selection` — read and mutate the current scene selection.\n *\n * Selection targets are {@linkcode ComponentHandle}s. `get` is the one sanctioned\n * `get`-returns-array accessor (§4.1(3)). The mutators (`set`/`add`/`remove`/`clear`)\n * change the live selection and return the resulting selection snapshot — they are\n * **not undoable** (the engine fires a selection listener, no command), so the\n * returned {@linkcode PluginDesignChangeResult} is a committed-state snapshot.\n */\nexport abstract class PluginDesignSelectionApi {\n constructor() {}\n\n /**\n * Read the current scene selection — the entities the user (or a previous\n * call) has selected, returned as handles you can pass straight into other\n * API calls.\n *\n * @returns The selection as {@linkcode ComponentHandle}`[]` (`[]` when nothing is selected)\n *\n * @examplePrompt What do I have selected right now?\n * @examplePrompt List the currently selected objects\n * @examplePrompt Which rooms are selected in the scene?\n * @examplePrompt Get the ids of everything I've selected\n * @examplePrompt Is anything selected?\n *\n * # Example\n * ```ts\n * // Selection handles feed straight into other API calls\n * const selection = await snaptrude.design.selection.get()\n * if (selection.length > 0) {\n * const props = await snaptrude.design.query.getProperties(selection[0])\n * }\n * ```\n */\n public abstract get(): PluginApiReturn<ComponentHandle[]>\n\n /**\n * Replace the selection with exactly the given entities — anything\n * previously selected is deselected first, so afterwards only these\n * entities are selected.\n *\n * @param components The entities to select\n * @returns The resulting selection snapshot\n *\n * @examplePrompt Select these three walls\n * @examplePrompt Select only the kitchen and deselect everything else\n * @examplePrompt Change the selection to just these rooms\n * @examplePrompt Highlight the spaces on the second storey\n *\n * # Example\n * ```ts\n * // Select only the ground-storey walls (replaces the previous selection)\n * const walls = await snaptrude.design.query.listWalls({ storeys: [1] })\n * const { affected } = await snaptrude.design.selection.set(walls)\n * ```\n */\n public abstract set(components: ComponentHandle[]): PluginApiReturn<PluginDesignChangeResult>\n\n /**\n * Add entities to the current selection without deselecting anything — the\n * selection grows to include the given entities alongside whatever was\n * already selected.\n *\n * @param components The entities to add to the selection\n * @returns The resulting selection snapshot\n *\n * @examplePrompt Add the corridor to my current selection\n * @examplePrompt Select these columns too, keeping what's already selected\n * @examplePrompt Also select the roof\n * @examplePrompt Extend the selection to include all the doors on this floor\n *\n * # Example\n * ```ts\n * // Grow the selection to include every roof, keeping what's already selected\n * const roofs = await snaptrude.design.query.listRoofs()\n * await snaptrude.design.selection.add(roofs)\n * ```\n */\n public abstract add(components: ComponentHandle[]): PluginApiReturn<PluginDesignChangeResult>\n\n /**\n * Remove entities from the current selection — the given entities are\n * deselected while everything else stays selected.\n *\n * @param components The entities to remove from the selection\n * @returns The resulting selection snapshot\n *\n * @examplePrompt Deselect the stair core but keep the rest selected\n * @examplePrompt Remove these walls from my selection\n * @examplePrompt Take the furniture out of the current selection\n * @examplePrompt Unselect the two smaller rooms\n *\n * # Example\n * ```ts\n * // Deselect the furniture while keeping everything else selected\n * const furniture = await snaptrude.design.query.listFurniture({ isSelected: true })\n * await snaptrude.design.selection.remove(furniture)\n * ```\n */\n public abstract remove(\n components: ComponentHandle[]\n ): PluginApiReturn<PluginDesignChangeResult>\n\n /**\n * Clear the selection so nothing is selected (equivalent to `set([])`).\n *\n * @returns The resulting (empty) selection snapshot\n *\n * @examplePrompt Deselect everything\n * @examplePrompt Clear my current selection\n * @examplePrompt Unselect all objects in the scene\n * @examplePrompt Make sure nothing is selected before we start\n *\n * # Example\n * ```ts\n * const { affected } = await snaptrude.design.selection.clear()\n * // affected is the resulting selection — always [] here\n * ```\n */\n public abstract clear(): PluginApiReturn<PluginDesignChangeResult>\n}\n\n/**\n * Arguments for {@linkcode PluginDesignSelectionApi.set}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `components` | {@linkcode ComponentHandle}`[]` | The entities to select |\n */\nexport const PluginDesignSelectionSetArgs = z.object({\n components: z.array(ComponentHandle),\n})\nexport type PluginDesignSelectionSetArgs = z.infer<typeof PluginDesignSelectionSetArgs>\n\nexport const PluginDesignSelectionAddArgs = PluginDesignSelectionSetArgs\nexport type PluginDesignSelectionAddArgs = z.infer<typeof PluginDesignSelectionAddArgs>\n\nexport const PluginDesignSelectionRemoveArgs = PluginDesignSelectionSetArgs\nexport type PluginDesignSelectionRemoveArgs = z.infer<typeof PluginDesignSelectionRemoveArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { ComponentHandle } from \"../../../handles\"\nimport { PluginDesignChangeResult } from \"../lock\"\n\n/**\n * `snaptrude.design.doors` — door-specific reads + edits. Creation lives at\n * `design.create.door`; generic reads (`listDoors`/`getHost`/`getProperties`) live at\n * `design.query.*`. Door targets are {@linkcode ComponentHandle}s.\n *\n * `getSwingDirection` is a DERIVED read (no persisted field) — computed from the door\n * mesh reflection state. `mirror` reflects the door across an axis (undoable, one\n * command); `setType` is intentionally absent (the engine has no in-place re-type —\n * it would require delete+recreate).\n */\nexport abstract class PluginDesignDoorsApi {\n constructor() {}\n\n /**\n * Get the type name of a door — the label that identifies which kind of door\n * the instance is, as shown in its properties.\n *\n * @param door The door to query\n * @returns The type as a `string`, or `null`\n *\n * @examplePrompt What type of door is this?\n * @examplePrompt Tell me the door type of the selected door\n * @examplePrompt Is this a single or a double door?\n * @examplePrompt Check what kind of door is on this wall\n *\n * # Example\n * ```ts\n * const [door] = await snaptrude.design.query.listDoors({ isSelected: true })\n * const type = await snaptrude.design.doors.getType(door)\n * if (type) console.log(\"door type:\", type)\n * ```\n */\n public abstract getType(door: ComponentHandle): PluginApiReturn<string | null>\n\n /**\n * Get the family name of a door — the Revit or native family the door\n * instance comes from.\n *\n * @param door The door to query\n * @returns The family as a `string`, or `null`\n *\n * @examplePrompt Which family does this door belong to?\n * @examplePrompt What's the Revit family of the selected door?\n * @examplePrompt Show the family name for this door\n * @examplePrompt Find out which door family the imported door uses\n *\n * # Example\n * ```ts\n * const [door] = await snaptrude.design.query.listDoors()\n * const family = await snaptrude.design.doors.getFamily(door)\n * if (family) console.log(\"family:\", family)\n * ```\n */\n public abstract getFamily(door: ComponentHandle): PluginApiReturn<string | null>\n\n /**\n * Get the width of a door — how wide its opening is along the host wall.\n *\n * @param door The door to query\n * @returns The width as a `number`, or `null`\n *\n * @examplePrompt How wide is this door?\n * @examplePrompt What's the width of the selected door?\n * @examplePrompt Measure the width of the entrance door\n * @examplePrompt Check whether this door is 900mm wide\n *\n * # Example\n * ```ts\n * const [door] = await snaptrude.design.query.listDoors({ isSelected: true })\n * const width = await snaptrude.design.doors.getWidth(door)\n * if (width !== null) console.log(\"door width:\", width)\n * ```\n */\n public abstract getWidth(door: ComponentHandle): PluginApiReturn<number | null>\n\n /**\n * Get the height of a door — how tall its opening is from base to head.\n *\n * @param door The door to query\n * @returns The height as a `number`, or `null`\n *\n * @examplePrompt How tall is this door?\n * @examplePrompt What's the height of the selected door?\n * @examplePrompt Check the door height for this opening\n * @examplePrompt Is the front door 2100mm high?\n *\n * # Example\n * ```ts\n * const [door] = await snaptrude.design.query.listDoors()\n * const height = await snaptrude.design.doors.getHeight(door)\n * if (height !== null) console.log(\"door height:\", height)\n * ```\n */\n public abstract getHeight(door: ComponentHandle): PluginApiReturn<number | null>\n\n /**\n * Get the floor a door is hosted on — the storey/level component that\n * supports the door.\n *\n * @param door The door to query\n * @returns The support floor {@linkcode ComponentHandle}, or `null`\n *\n * @examplePrompt Which floor is this door on?\n * @examplePrompt What storey does the selected door belong to?\n * @examplePrompt Find the level that hosts this door\n * @examplePrompt Tell me which floor the entrance door sits on\n *\n * # Example\n * ```ts\n * const [door] = await snaptrude.design.query.listDoors({ isSelected: true })\n * const floor = await snaptrude.design.doors.getSupportFloor(door)\n * if (floor) {\n * const props = await snaptrude.design.query.getProperties(floor)\n * console.log(\"hosted on storey:\", props.storey)\n * }\n * ```\n */\n public abstract getSupportFloor(door: ComponentHandle): PluginApiReturn<ComponentHandle | null>\n\n /**\n * Get a door's swing (hinge) handedness — whether it opens as a left-hand or\n * right-hand door. Derived from the door mesh's reflection state, not a\n * persisted field.\n *\n * @param door The door to query\n * @returns `'left'` / `'right'`, or `null` if indeterminate\n *\n * @examplePrompt Which way does this door swing?\n * @examplePrompt Is the selected door left-handed or right-handed?\n * @examplePrompt Check the hinge side of this door\n * @examplePrompt Does the entrance door open to the left or the right?\n *\n * # Example\n * ```ts\n * const [door] = await snaptrude.design.query.listDoors({ isSelected: true })\n * const swing = await snaptrude.design.doors.getSwingDirection(door)\n * if (swing) console.log(\"opens as a\", swing, \"hand door\")\n * ```\n */\n public abstract getSwingDirection(\n door: ComponentHandle\n ): PluginApiReturn<\"left\" | \"right\" | null>\n\n /**\n * Mirror a door across an axis, flipping its swing so it opens from the\n * other side. Undoable as a single command.\n *\n * @param door The door to mirror\n * @param axis Reflection axis (optional; default `'x'` — the swing-flip axis)\n * @returns The affected door(s)\n *\n * @examplePrompt Flip this door's swing\n * @examplePrompt Mirror the selected door\n * @examplePrompt Make this door open the other way\n * @examplePrompt Reverse the hinge side of the entrance door\n * @examplePrompt Change the door to swing from the other side\n *\n * # Example\n * ```ts\n * // Flip the selected door's swing — axis defaults to \"x\" (the swing-flip\n * // axis); pass \"y\" or \"z\" to reflect across a different axis\n * const [door] = await snaptrude.design.query.listDoors({ isSelected: true })\n * const { affected } = await snaptrude.design.doors.mirror(door)\n * ```\n */\n public abstract mirror(\n door: ComponentHandle,\n axis?: PluginMirrorAxis\n ): PluginApiReturn<PluginDesignChangeResult>\n\n /**\n * Set the width of one or more doors, resizing each opening and re-cutting\n * the host wall. Width is in engine units; the change is undoable.\n *\n * @param doors The doors to resize\n * @param width New width (engine units)\n * @returns The affected doors\n *\n * @examplePrompt Make this door 900mm wide\n * @examplePrompt Widen the selected doors to 1 metre\n * @examplePrompt Change the door width to 3 feet\n * @examplePrompt Resize all the bathroom doors to 750 wide\n * @examplePrompt Narrow the entrance door a bit\n *\n * # Example\n * ```ts\n * // Resize every ground-floor door to a common width (engine units)\n * const doors = await snaptrude.design.query.listDoors({ storeys: [1] })\n * const { affected } = await snaptrude.design.doors.setWidth(doors, 900)\n * console.log(\"resized\", affected.length, \"doors\")\n * ```\n */\n public abstract setWidth(\n doors: ComponentHandle[],\n width: number\n ): PluginApiReturn<PluginDesignChangeResult>\n\n /**\n * Set the height of one or more doors, resizing each opening and re-cutting\n * the host wall. Height is in engine units; the change is undoable.\n *\n * @param doors The doors to resize\n * @param height New height (engine units)\n * @returns The affected doors\n *\n * @examplePrompt Make this door 2100mm tall\n * @examplePrompt Change the door height to 7 feet\n * @examplePrompt Raise the selected doors to 2.4m high\n * @examplePrompt Set all the doors on this storey to 2100 high\n *\n * # Example\n * ```ts\n * // setHeight takes an array — wrap a single door\n * const [door] = await snaptrude.design.query.listDoors({ isSelected: true })\n * await snaptrude.design.doors.setHeight([door], 2100)\n * ```\n */\n public abstract setHeight(\n doors: ComponentHandle[],\n height: number\n ): PluginApiReturn<PluginDesignChangeResult>\n}\n\n/**\n * Arguments for the single-door read methods.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `door` | {@linkcode ComponentHandle} | The door to query |\n */\nexport const PluginDesignDoorArgs = z.object({\n door: ComponentHandle,\n})\nexport type PluginDesignDoorArgs = z.infer<typeof PluginDesignDoorArgs>\n\n/** Mirror axis — tokens mirror the engine `FlipDirection` verbatim (§6.1). */\nexport const PluginMirrorAxis = z.enum([\"x\", \"y\", \"z\"])\nexport type PluginMirrorAxis = z.infer<typeof PluginMirrorAxis>\n\n/**\n * Arguments for {@linkcode PluginDesignDoorsApi.mirror}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `door` | {@linkcode ComponentHandle} | The door to mirror |\n * | `axis` | {@linkcode PluginMirrorAxis} | Reflection axis (optional; default `'x'` — the swing-flip axis) |\n */\nexport const PluginDesignDoorMirrorArgs = z.object({\n door: ComponentHandle,\n axis: PluginMirrorAxis.optional(),\n})\nexport type PluginDesignDoorMirrorArgs = z.infer<typeof PluginDesignDoorMirrorArgs>\n\n/**\n * Arguments for {@linkcode PluginDesignDoorsApi.setWidth}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `doors` | {@linkcode ComponentHandle}`[]` | The doors to resize |\n * | `width` | `number` | New width (engine units) |\n */\nexport const PluginDesignDoorSetWidthArgs = z.object({\n doors: z.array(ComponentHandle),\n width: z.number(),\n})\nexport type PluginDesignDoorSetWidthArgs = z.infer<typeof PluginDesignDoorSetWidthArgs>\n\n/**\n * Arguments for {@linkcode PluginDesignDoorsApi.setHeight}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `doors` | {@linkcode ComponentHandle}`[]` | The doors to resize |\n * | `height` | `number` | New height (engine units) |\n */\nexport const PluginDesignDoorSetHeightArgs = z.object({\n doors: z.array(ComponentHandle),\n height: z.number(),\n})\nexport type PluginDesignDoorSetHeightArgs = z.infer<typeof PluginDesignDoorSetHeightArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { ComponentHandle } from \"../../../handles\"\nimport { PluginDesignChangeResult } from \"../lock\"\n\n/**\n * `snaptrude.design.windows` — window-specific reads. Creation lives at\n * `design.create.window`; generic reads (`listWindows`/`getHost`/`getProperties`) live\n * at `design.query.*`. Window targets are {@linkcode ComponentHandle}s.\n *\n * `listTypes` (UI-const catalog), `getSillHeight` (bounds-derived), and the\n * command-wired `mirror` land in a later pass.\n */\nexport abstract class PluginDesignWindowsApi {\n constructor() {}\n\n /**\n * Get the type name of a window — the label that identifies which kind of\n * window the instance is, as shown in its properties.\n *\n * @param window The window to query\n * @returns The type as a `string`, or `null`\n *\n * @examplePrompt What type of window is this?\n * @examplePrompt Is the selected window a casement or a slider?\n * @examplePrompt Tell me the window type used on this wall\n * @examplePrompt Check what kind of window the living room has\n *\n * # Example\n * ```ts\n * const [win] = await snaptrude.design.query.listWindows({ isSelected: true })\n * const type = await snaptrude.design.windows.getType(win)\n * if (type) console.log(\"window type:\", type)\n * ```\n */\n public abstract getType(window: ComponentHandle): PluginApiReturn<string | null>\n\n /**\n * Get the width of a window — how wide its opening is along the host wall.\n *\n * @param window The window to query\n * @returns The width as a `number`, or `null`\n *\n * @examplePrompt How wide is this window?\n * @examplePrompt What's the width of the selected window?\n * @examplePrompt Measure the width of the kitchen window\n * @examplePrompt Check whether this window is 1200mm wide\n *\n * # Example\n * ```ts\n * const [win] = await snaptrude.design.query.listWindows()\n * const width = await snaptrude.design.windows.getWidth(win)\n * if (width !== null) console.log(\"window width:\", width)\n * ```\n */\n public abstract getWidth(window: ComponentHandle): PluginApiReturn<number | null>\n\n /**\n * Get the height of a window — how tall its opening is on the host wall.\n *\n * @param window The window to query\n * @returns The height as a `number`, or `null`\n *\n * @examplePrompt How tall is this window?\n * @examplePrompt What's the height of the selected window?\n * @examplePrompt Check the window height on this wall\n * @examplePrompt Is the bedroom window 1.5m high?\n *\n * # Example\n * ```ts\n * const [win] = await snaptrude.design.query.listWindows()\n * const height = await snaptrude.design.windows.getHeight(win)\n * if (height !== null) console.log(\"window height:\", height)\n * ```\n */\n public abstract getHeight(window: ComponentHandle): PluginApiReturn<number | null>\n\n /**\n * Get a window's full dimensions in one call — width along the wall, vertical\n * height, and thickness through the wall — measured in the window's local\n * oriented space.\n *\n * @param window The window to query\n * @returns The dimensions, or `null`\n *\n * @examplePrompt What are the dimensions of this window?\n * @examplePrompt How big is the selected window?\n * @examplePrompt Give me the width, height and depth of this window\n * @examplePrompt Measure the living room window\n * @examplePrompt Get the window size including its thickness through the wall\n *\n * # Example\n * ```ts\n * const [win] = await snaptrude.design.query.listWindows({ isSelected: true })\n * const dims = await snaptrude.design.windows.getDimensions(win)\n * if (dims) console.log(dims.width, dims.height, dims.thickness)\n * ```\n */\n public abstract getDimensions(\n window: ComponentHandle\n ): PluginApiReturn<PluginWindowDimensions | null>\n\n /**\n * Set the width of a window, resizing its opening and re-cutting the host\n * wall. Width is in engine units; the change is undoable.\n *\n * @param window The window to resize\n * @param width New width (engine units)\n * @returns The affected window\n *\n * @examplePrompt Make this window 1200mm wide\n * @examplePrompt Widen the selected window to 4 feet\n * @examplePrompt Change the window width to 1.5m\n * @examplePrompt Resize the kitchen window to 900 wide\n *\n * # Example\n * ```ts\n * // Takes a single window (unlike design.doors.setWidth, which takes an array)\n * const [win] = await snaptrude.design.query.listWindows({ isSelected: true })\n * const { affected } = await snaptrude.design.windows.setWidth(win, 1200)\n * ```\n */\n public abstract setWidth(\n window: ComponentHandle,\n width: number\n ): PluginApiReturn<PluginDesignChangeResult>\n\n /**\n * Set the height of a window, resizing its opening and re-cutting the host\n * wall. Height is in engine units; the change is undoable.\n *\n * @param window The window to resize\n * @param height New height (engine units)\n * @returns The affected window\n *\n * @examplePrompt Make this window 1.5m tall\n * @examplePrompt Change the window height to 4 feet\n * @examplePrompt Shorten the selected window to 900mm high\n * @examplePrompt Set the bedroom window height to 1200\n *\n * # Example\n * ```ts\n * const [win] = await snaptrude.design.query.listWindows({ isSelected: true })\n * await snaptrude.design.windows.setHeight(win, 1500)\n * ```\n */\n public abstract setHeight(\n window: ComponentHandle,\n height: number\n ): PluginApiReturn<PluginDesignChangeResult>\n}\n\n/**\n * Arguments for the single-window read methods.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `window` | {@linkcode ComponentHandle} | The window to query |\n */\nexport const PluginDesignWindowArgs = z.object({\n window: ComponentHandle,\n})\nexport type PluginDesignWindowArgs = z.infer<typeof PluginDesignWindowArgs>\n\n/**\n * A window's dimensions.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `width` | `number` | Along the wall |\n * | `height` | `number` | Vertical |\n * | `thickness` | `number` | Through the wall (engine `length` axis) |\n */\nexport const PluginWindowDimensions = z.object({\n width: z.number(),\n height: z.number(),\n thickness: z.number(),\n})\nexport type PluginWindowDimensions = z.infer<typeof PluginWindowDimensions>\n\n/**\n * Arguments for {@linkcode PluginDesignWindowsApi.setWidth}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `window` | {@linkcode ComponentHandle} | The window to resize |\n * | `width` | `number` | New width (engine units) |\n */\nexport const PluginDesignWindowSetWidthArgs = z.object({\n window: ComponentHandle,\n width: z.number(),\n})\nexport type PluginDesignWindowSetWidthArgs = z.infer<typeof PluginDesignWindowSetWidthArgs>\n\n/**\n * Arguments for {@linkcode PluginDesignWindowsApi.setHeight}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `window` | {@linkcode ComponentHandle} | The window to resize |\n * | `height` | `number` | New height (engine units) |\n */\nexport const PluginDesignWindowSetHeightArgs = z.object({\n window: ComponentHandle,\n height: z.number(),\n})\nexport type PluginDesignWindowSetHeightArgs = z.infer<typeof PluginDesignWindowSetHeightArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\n\n/**\n * `snaptrude.design.furniture` — the placeable furniture **catalog** (a library of\n * source items, NOT scene entities). Placement lives at `design.create.furniture`\n * (returns a {@linkcode ComponentHandle}); reads of placed furniture live at\n * `design.query.listFurniture`/`getProperties`.\n *\n * Catalog items are plain value records ({@linkcode PluginFurnitureCatalogItem}) keyed\n * by a library id (team `_id` or general `fullName`) — not handles. Reads are async\n * (network-backed) but carry no `Async` suffix (§6.6).\n */\nexport abstract class PluginDesignFurnitureApi {\n constructor() {}\n\n /**\n * List the placeable furniture catalog (team + general libraries).\n * @param source Restrict to one library (optional)\n * @returns The catalog as {@linkcode PluginFurnitureCatalogItem}`[]` (`[]` when empty)\n *\n * @examplePrompt What furniture can I place in this project?\n * @examplePrompt Show me all the furniture available in the library\n * @examplePrompt List the chairs and tables I can add to the model\n * @examplePrompt Which furniture items are in my team's library?\n * @examplePrompt Browse the furniture catalog\n *\n * # Example\n * ```ts\n * const teamItems = await snaptrude.design.furniture.listCatalog(\"team\")\n * for (const item of teamItems) console.log(item.id, item.name, item.cost)\n * ```\n */\n public abstract listCatalog(\n source?: \"team\" | \"general\"\n ): PluginApiReturn<PluginFurnitureCatalogItem[]>\n\n /**\n * Get a single catalog item by its library id.\n * @param id The catalog library id\n * @returns The item, or `null` if no catalog item matches\n *\n * @examplePrompt Get the details of this furniture item from the library\n * @examplePrompt Look up the catalog entry for this chair id\n * @examplePrompt What is the cost of this furniture item?\n * @examplePrompt Show me the family name of the sofa in the catalog\n *\n * # Example\n * ```ts\n * const [entry] = await snaptrude.design.furniture.listCatalog()\n * const item = await snaptrude.design.furniture.getCatalogItem(entry.id)\n * if (item) console.log(item.name, item.source, item.familyName)\n * ```\n */\n public abstract getCatalogItem(\n id: string\n ): PluginApiReturn<PluginFurnitureCatalogItem | null>\n\n /**\n * Test whether a catalog item exists for the given library id.\n * @param id The catalog library id\n * @returns `true` if it exists, otherwise `false`\n *\n * @examplePrompt Is this furniture item still in the library?\n * @examplePrompt Check whether a catalog item with this id exists\n * @examplePrompt Does my team library have this chair?\n * @examplePrompt Verify the sofa is available in the catalog before placing it\n *\n * # Example\n * ```ts\n * const [entry] = await snaptrude.design.furniture.listCatalog()\n * const stillAvailable = await snaptrude.design.furniture.exists(entry.id)\n * console.log(stillAvailable ? \"safe to place\" : \"removed from library\")\n * ```\n */\n public abstract exists(id: string): PluginApiReturn<boolean>\n}\n\n/**\n * A placeable furniture catalog item (value record — not a scene entity/handle).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Library id (team `_id` or general `fullName`) — pass to `design.create.furniture` |\n * | `name` | `string` | Display name |\n * | `source` | `'team' \\| 'general'` | Which library it came from |\n * | `subType` | `string` | Sub-type (optional) |\n * | `cost` | `number` | Cost (optional; team items) |\n * | `familyName` | `string` | Family name (optional) |\n */\nexport const PluginFurnitureCatalogItem = z.object({\n id: z.string(),\n name: z.string(),\n source: z.enum([\"team\", \"general\"]),\n subType: z.string().optional(),\n cost: z.number().optional(),\n familyName: z.string().optional(),\n})\nexport type PluginFurnitureCatalogItem = z.infer<typeof PluginFurnitureCatalogItem>\n\n/**\n * Arguments for {@linkcode PluginDesignFurnitureApi.listCatalog}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `source` | `'team' \\| 'general'` | Restrict to one library (optional) |\n */\nexport const PluginDesignFurnitureListCatalogArgs = z.object({\n source: z.enum([\"team\", \"general\"]).optional(),\n})\nexport type PluginDesignFurnitureListCatalogArgs = z.infer<\n typeof PluginDesignFurnitureListCatalogArgs\n>\n\n/**\n * Arguments for {@linkcode PluginDesignFurnitureApi.getCatalogItem} / {@linkcode PluginDesignFurnitureApi.exists}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | The catalog library id |\n */\nexport const PluginDesignFurnitureGetCatalogItemArgs = z.object({\n id: z.string(),\n})\nexport type PluginDesignFurnitureGetCatalogItemArgs = z.infer<\n typeof PluginDesignFurnitureGetCatalogItemArgs\n>\n\nexport const PluginDesignFurnitureExistsArgs = PluginDesignFurnitureGetCatalogItemArgs\nexport type PluginDesignFurnitureExistsArgs = z.infer<typeof PluginDesignFurnitureExistsArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { ComponentHandle, MaterialHandle } from \"../../../handles\"\n\n/**\n * `snaptrude.design.materials` — the project material library + material assignment.\n *\n * Materials are {@linkcode MaterialHandle}s (entity-style, name-addressed). Reads return\n * a {@linkcode MaterialHandle}/{@linkcode PluginMaterialInfo}; `apply`/`reset` mutate the\n * scene (undoable via `save`, default `true`). `create` mints a material from a\n * {@linkcode PluginMaterialSpec} (idempotent by name).\n *\n * Face-targeted apply, per-face reads (`listByFace`), and `copy` (needs an undo\n * wrapper) land in a later pass.\n */\nexport abstract class PluginDesignMaterialsApi {\n constructor() {}\n\n /**\n * List the project materials.\n * @param scope Which library to list (optional)\n * @returns The materials as {@linkcode MaterialHandle}`[]`\n *\n * @examplePrompt List all the materials in this project\n * @examplePrompt What materials do I have available to apply?\n * @examplePrompt Show me the preset materials library\n * @examplePrompt Which finishes exist in this model?\n * @examplePrompt Get every material in the project palette\n *\n * # Example\n * ```ts\n * const presets = await snaptrude.design.materials.list(\"preset\")\n * console.log(presets.length, \"preset materials\")\n * ```\n */\n public abstract list(scope?: \"project\" | \"preset\"): PluginApiReturn<MaterialHandle[]>\n\n /**\n * Read a material's descriptor — its name, color, opacity, and texture\n * (when it has one).\n *\n * @param material The material to read\n * @returns The {@linkcode PluginMaterialInfo}, or `null` if the material is gone\n *\n * @examplePrompt What colour is the Brick material?\n * @examplePrompt Show me the details of this material\n * @examplePrompt Get the opacity of the glass finish\n * @examplePrompt Which texture image does the wood material use?\n *\n * # Example\n * ```ts\n * const [material] = await snaptrude.design.materials.list()\n * const info = await snaptrude.design.materials.getInfo(material)\n * if (info) console.log(info.name, info.colorHex, info.alpha)\n * ```\n */\n public abstract getInfo(material: MaterialHandle): PluginApiReturn<PluginMaterialInfo | null>\n\n /**\n * Apply a material to one or more components — an existing project material by\n * handle, or a new one described inline as a {@linkcode PluginMaterialSpec}.\n * Undoable when `save` is true (the default).\n *\n * @param targets Components to paint\n * @param material Material handle, or an inline {@linkcode PluginMaterialSpec}\n * @param save Commit as an undoable command (default `true`)\n * @returns The number of targets the material was applied to\n *\n * @examplePrompt Paint the selected walls red\n * @examplePrompt Apply the brick material to these walls\n * @examplePrompt Put a wood finish on the floor\n * @examplePrompt Change the colour of this room's walls to #ff8800\n * @examplePrompt Add a concrete texture to the facade\n *\n * # Example\n * ```ts\n * const walls = await snaptrude.design.query.listWalls({ storeys: [1] })\n * // inline spec — creates (or reuses by name) a project material, then applies it\n * const { count } = await snaptrude.design.materials.apply(walls, { name: \"Accent Red\", color: \"#b04a3a\" })\n * console.log(\"painted\", count, \"walls\")\n * ```\n */\n public abstract apply(\n targets: ComponentHandle[],\n material: MaterialHandle | PluginMaterialSpec,\n save?: boolean\n ): PluginApiReturn<PluginMaterialResult>\n\n /**\n * Reset one or more components back to the default material for their type,\n * removing any applied finish. The inverse of `apply`; undoable when `save`\n * is true (the default).\n *\n * @param components Components to reset\n * @param save Commit as an undoable command (default `true`)\n * @returns The number of components reset\n *\n * @examplePrompt Remove the paint from these walls\n * @examplePrompt Reset the selected objects to their default material\n * @examplePrompt Clear the custom finish on the floor\n * @examplePrompt Restore the original colour of this roof\n *\n * # Example\n * ```ts\n * const selected = await snaptrude.design.selection.get()\n * const { count } = await snaptrude.design.materials.reset(selected)\n * console.log(\"reset\", count, \"components to their default material\")\n * ```\n */\n public abstract reset(\n components: ComponentHandle[],\n save?: boolean\n ): PluginApiReturn<PluginMaterialResult>\n\n /**\n * Create a new material in the project from a spec — a color, texture URL,\n * opacity, and/or name. Idempotent by name: creating with the name of an\n * existing material returns that material instead of duplicating it.\n *\n * @param spec The material construction spec\n * @returns The new material as a {@linkcode MaterialHandle}\n *\n * @examplePrompt Create a new red material called Accent\n * @examplePrompt Make a material from this texture image URL\n * @examplePrompt Add a semi-transparent glass material to the project\n * @examplePrompt Define a dark grey concrete finish I can reuse\n *\n * # Example\n * ```ts\n * const glass = await snaptrude.design.materials.create({ name: \"Frosted Glass\", color: \"#cfe4e8\", alpha: 0.4 })\n * const walls = await snaptrude.design.query.listWalls({ storeys: [1] })\n * await snaptrude.design.materials.apply(walls, glass)\n * ```\n */\n public abstract create(spec: PluginMaterialSpec): PluginApiReturn<MaterialHandle>\n\n /**\n * Get the default material for a component's type.\n * @param component The component to look up\n * @returns The default material as a {@linkcode MaterialHandle}, or `null`\n *\n * @examplePrompt What is the default material for walls?\n * @examplePrompt Get the standard material this floor type uses\n * @examplePrompt Which material would this roof have out of the box?\n * @examplePrompt Find the default finish for the selected column\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const defaultMaterial = await snaptrude.design.materials.getDefault(wall)\n * if (defaultMaterial) console.log(await snaptrude.design.materials.getInfo(defaultMaterial))\n * ```\n */\n public abstract getDefault(component: ComponentHandle): PluginApiReturn<MaterialHandle | null>\n\n /**\n * Test whether a component carries its (type) default material.\n * @param component The component to test\n * @returns `true` if default, otherwise `false`\n *\n * @examplePrompt Is this wall still using its default material?\n * @examplePrompt Has the material on this floor been changed?\n * @examplePrompt Check if the selected object still has its original finish\n * @examplePrompt Tell me whether this roof has been painted or is still standard\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const untouched = await snaptrude.design.materials.isDefault(wall)\n * console.log(untouched ? \"still default\" : \"has been painted\")\n * ```\n */\n public abstract isDefault(component: ComponentHandle): PluginApiReturn<boolean>\n\n /**\n * Test whether a component has a single (uniform) material across all faces.\n * @param component The component to test\n * @returns `true` if uniform, otherwise `false`\n *\n * @examplePrompt Does this wall have the same material on every face?\n * @examplePrompt Is the floor finished uniformly or face by face?\n * @examplePrompt Check if this column is a single material all over\n * @examplePrompt Are any faces of the selected object painted differently?\n *\n * # Example\n * ```ts\n * const [selected] = await snaptrude.design.selection.get()\n * const uniform = await snaptrude.design.materials.isUniform(selected)\n * console.log(uniform ? \"one material all over\" : \"painted per face\")\n * ```\n */\n public abstract isUniform(component: ComponentHandle): PluginApiReturn<boolean>\n\n /**\n * Test whether a material has a texture.\n * @param material The material to test\n * @returns `true` if it has a diffuse texture, otherwise `false`\n *\n * @examplePrompt Does this material have a texture image?\n * @examplePrompt Is the brick material textured or just a flat colour?\n * @examplePrompt Check whether the wood finish uses an image map\n * @examplePrompt Tell me if this material is image-based or a plain colour\n *\n * # Example\n * ```ts\n * const [material] = await snaptrude.design.materials.list()\n * const textured = await snaptrude.design.materials.hasTexture(material)\n * console.log(textured ? \"image-based\" : \"flat colour\")\n * ```\n */\n public abstract hasTexture(material: MaterialHandle): PluginApiReturn<boolean>\n}\n\n/**\n * A material's descriptor.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string` | Material name (== the handle token) |\n * | `id` | `string` | Engine material id |\n * | `colorHex` | `string` | Diffuse color as `#rrggbb` |\n * | `alpha` | `number` | Opacity `0..1` |\n * | `materialType` | `string` | Material type tag (optional) |\n * | `textureUrl` | `string` | Diffuse texture URL (optional) |\n */\nexport const PluginMaterialInfo = z.object({\n name: z.string(),\n id: z.string(),\n colorHex: z.string(),\n alpha: z.number(),\n materialType: z.string().optional(),\n textureUrl: z.string().optional(),\n})\nexport type PluginMaterialInfo = z.infer<typeof PluginMaterialInfo>\n\n/**\n * A material construction spec (input DTO — NOT a handle).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string` | Name (optional; generated if omitted) |\n * | `color` | `string` | Diffuse color `#rrggbb` (optional) |\n * | `textureUrl` | `string` | Diffuse texture URL (optional; wins over color) |\n * | `alpha` | `number` | Opacity `0..1` (optional) |\n * | `materialType` | `string` | Material type tag (optional) |\n */\nexport const PluginMaterialSpec = z.object({\n name: z.string().optional(),\n color: z.string().optional(),\n textureUrl: z.string().optional(),\n alpha: z.number().optional(),\n materialType: z.string().optional(),\n})\nexport type PluginMaterialSpec = z.infer<typeof PluginMaterialSpec>\n\n/** Result of a material mutation — the count of targets affected. */\nexport const PluginMaterialResult = z.object({ count: z.number() })\nexport type PluginMaterialResult = z.infer<typeof PluginMaterialResult>\n\n/** Arguments for {@linkcode PluginDesignMaterialsApi.list}. */\nexport const PluginDesignMaterialsListArgs = z.object({\n scope: z.enum([\"project\", \"preset\"]).optional(),\n})\nexport type PluginDesignMaterialsListArgs = z.infer<typeof PluginDesignMaterialsListArgs>\n\n/** Arguments for {@linkcode PluginDesignMaterialsApi.getInfo} / `hasTexture`. */\nexport const PluginDesignMaterialsGetInfoArgs = z.object({ material: MaterialHandle })\nexport type PluginDesignMaterialsGetInfoArgs = z.infer<typeof PluginDesignMaterialsGetInfoArgs>\n\n/** Arguments for component-scoped predicates (`getDefault`/`isDefault`/`isUniform`). */\nexport const PluginDesignMaterialsComponentArgs = z.object({ component: ComponentHandle })\nexport type PluginDesignMaterialsComponentArgs = z.infer<\n typeof PluginDesignMaterialsComponentArgs\n>\n\n/**\n * Arguments for {@linkcode PluginDesignMaterialsApi.apply}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `targets` | {@linkcode ComponentHandle}`[]` | Components to paint |\n * | `material` | {@linkcode MaterialHandle} \\| {@linkcode PluginMaterialSpec} | Material handle, or an inline spec |\n * | `save` | `boolean` | Commit as an undoable command (default `true`) |\n */\nexport const PluginDesignMaterialsApplyArgs = z.object({\n targets: z.array(ComponentHandle),\n material: z.union([MaterialHandle, PluginMaterialSpec]),\n save: z.boolean().optional(),\n})\nexport type PluginDesignMaterialsApplyArgs = z.infer<typeof PluginDesignMaterialsApplyArgs>\n\n/** Arguments for {@linkcode PluginDesignMaterialsApi.reset}. */\nexport const PluginDesignMaterialsResetArgs = z.object({\n components: z.array(ComponentHandle),\n save: z.boolean().optional(),\n})\nexport type PluginDesignMaterialsResetArgs = z.infer<typeof PluginDesignMaterialsResetArgs>\n\n/** Arguments for {@linkcode PluginDesignMaterialsApi.create}. */\nexport const PluginDesignMaterialsCreateArgs = z.object({ spec: PluginMaterialSpec })\nexport type PluginDesignMaterialsCreateArgs = z.infer<typeof PluginDesignMaterialsCreateArgs>\n","import * as z from \"zod\"\nimport { ComponentHandle } from \"../../handles\"\n\n/**\n * Shared result for scene-state change mutations (lock/unlock, selection, visibility)\n * — echoes the handles actually affected (post-cascade for lock). Errors throw\n * (RPC rejects); there is no `Result<>` monad in the SDK (consistent with\n * `design.create.*` returning a handle directly).\n */\nexport const PluginDesignChangeResult = z.object({\n affected: z.array(ComponentHandle),\n})\nexport type PluginDesignChangeResult = z.infer<typeof PluginDesignChangeResult>\n\n/**\n * Arguments for {@linkcode PluginDesignApi.lock} / {@linkcode PluginDesignApi.unlock}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `components` | {@linkcode ComponentHandle}`[]` | Entities to lock / unlock |\n */\nexport const PluginDesignLockArgs = z.object({\n components: z.array(ComponentHandle),\n})\nexport type PluginDesignLockArgs = z.infer<typeof PluginDesignLockArgs>\n\nexport const PluginDesignUnlockArgs = PluginDesignLockArgs\nexport type PluginDesignUnlockArgs = z.infer<typeof PluginDesignUnlockArgs>\n\n/**\n * Arguments for {@linkcode PluginDesignApi.isLocked}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `component` | {@linkcode ComponentHandle} | The entity to test |\n * | `includeInherited` | `boolean` | Fold group + bucket lock (default `true`); `false` reads the own flag only |\n */\nexport const PluginDesignIsLockedArgs = z.object({\n component: ComponentHandle,\n includeInherited: z.boolean().optional(),\n})\nexport type PluginDesignIsLockedArgs = z.infer<typeof PluginDesignIsLockedArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { ComponentHandle, Vec3Handle } from \"../../../handles\"\n\n/**\n * The erase strategies exposed to plugins. `SplitAndUnion` is *enumerable* but\n * NOT committable via {@linkcode PluginDesignEraseApi.edge} (it needs an\n * interactive screen-space re-pick); `SplitAndDelete` is reserved in the engine\n * and intentionally omitted. Derived host-side by the engine's `decideStrategy`.\n */\nexport const EraseStrategy = z.enum([\"DirectDelete\", \"DirectUnion\", \"SplitAndUnion\"])\nexport type EraseStrategy = z.infer<typeof EraseStrategy>\n\n/** Default enumerated strategies — the two the scripted `edge()` can commit. */\nexport const DEFAULT_ERASE_STRATEGIES: readonly EraseStrategy[] = [\"DirectDelete\", \"DirectUnion\"]\n\n/**\n * A **transient** reference to one erasable edge in the current plan's\n * bottom-adjacency graph.\n *\n * ⚠️ **Lifetime**: valid ONLY until the next geometry-modifying operation. Any\n * mutation (erase, boolean, transform, create, delete, …) rebuilds the adjacency\n * graph and invalidates every previously-returned ref. Passing a stale ref to\n * {@linkcode PluginDesignEraseApi.edge} throws `NO_STRATEGY_FOR_PICK_INFO`.\n * Always re-list after a mutation.\n *\n * This is a by-value record (round-trip it back to `edge()` unmodified), NOT a\n * registry handle. `components` and `snapPoint` are the marshalled public forms\n * of the engine's raw `mesh.uniqueId` numbers / by-value point.\n */\nexport const ErasableEdgeRef = z.object({\n /** Opaque bottom-graph edge id (engine form `\"e-<n>\"`). Do not mutate. Pass verbatim to {@linkcode PluginDesignEraseApi.edge}. */\n id: z.string().min(1),\n /** What erasing this edge would do: `DirectDelete` drops a mass; `DirectUnion` merges two adjacent masses. */\n strategy: EraseStrategy,\n /** Bottom-graph edge weight: `1` = external boundary edge, `>=2` = internal edge shared between components. */\n edgeWeight: z.number(),\n /** The components this edge is incident to — one for external (DirectDelete), two for internal (DirectUnion). */\n components: z.array(ComponentHandle),\n /** A representative point on the edge (its head endpoint). Diagnostic only. */\n snapPoint: Vec3Handle,\n})\nexport type ErasableEdgeRef = z.infer<typeof ErasableEdgeRef>\n\n/**\n * Options for {@linkcode PluginDesignEraseApi.listErasableEdges}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `components` | {@linkcode ComponentHandle}`[]?` | Restrict to edges adjacent to at least one of these entities |\n * | `strategies` | {@linkcode EraseStrategy}`[]?` | Restrict to these strategies. Default `[\"DirectDelete\",\"DirectUnion\"]` (hides interactive-only `SplitAndUnion`) |\n *\n * TRANSPORT: positional now — `listErasableEdges(options?)`; this schema is\n * retained for host-side validation.\n */\nexport const PluginDesignListErasableEdgesArgs = z.object({\n components: z.array(ComponentHandle).optional(),\n strategies: z.array(EraseStrategy).optional(),\n})\nexport type PluginDesignListErasableEdgesArgs = z.infer<typeof PluginDesignListErasableEdgesArgs>\n\n/**\n * Arguments for {@linkcode PluginDesignEraseApi.edge}.\n *\n * TRANSPORT: positional now — `edge(edge: ErasableEdgeRef)`; this schema is\n * retained for host-side validation.\n */\nexport const PluginDesignEraseEdgeArgs = z.object({\n edge: ErasableEdgeRef,\n})\nexport type PluginDesignEraseEdgeArgs = z.infer<typeof PluginDesignEraseEdgeArgs>\n\n/** Result of {@linkcode PluginDesignEraseApi.edge} — success sentinel; the engine yields no survivor id. */\nexport const PluginDesignEraseEdgeResult = z.object({ ok: z.literal(true) })\nexport type PluginDesignEraseEdgeResult = z.infer<typeof PluginDesignEraseEdgeResult>\n\n/**\n * `snaptrude.design.erase` — **adjacency-edge erase** (plan-level topology op).\n *\n * Erase is NOT delete. The erase tool operates on an **edge**, and the effect is\n * derived from that edge: erasing an internal edge between two masses **unions**\n * them (`DirectUnion`); erasing an external boundary edge of a single mass\n * **drops** it behind the edge (`DirectDelete`). For hard entity removal use\n * `design.delete.entities`; for CSG geometry delete use `design.boolean.subtract`.\n *\n * Two-step: {@linkcode listErasableEdges} to enumerate, then {@linkcode edge} to\n * commit one ref (single undo entry). Scoped to **2D plan adjacency edges** in v1.\n *\n * TRANSPORT: positional args per method.\n */\nexport abstract class PluginDesignEraseApi {\n constructor() {}\n\n /**\n * Enumerate every erasable edge in the current plan's bottom-adjacency graph\n * (one {@linkcode ErasableEdgeRef} per edge). Pure read — no scene mutation, no\n * command, not undoable. Erase-ineligible components (locked, hidden, off-storey)\n * are filtered out.\n *\n * ⚠️ Returned refs are **transient** — see {@linkcode ErasableEdgeRef}. Re-list\n * after any geometry mutation.\n *\n * @param options - {@linkcode PluginDesignListErasableEdgesArgs} — optional filters (`components`, `strategies`)\n * @returns The erasable edges (`[]` when none) — never `null`.\n *\n * @examplePrompt Which edges in my floor plan can be erased?\n * @examplePrompt List the erasable edges on this storey\n * @examplePrompt Show me the shared edges I could erase to merge rooms\n * @examplePrompt What edges between these two spaces can be removed?\n *\n * # Example\n * ```ts\n * const edges = await snaptrude.design.erase.listErasableEdges()\n * const union = edges.find((e) => e.strategy === \"DirectUnion\")\n * if (union) await snaptrude.design.erase.edge(union)\n * ```\n */\n public abstract listErasableEdges(\n options?: PluginDesignListErasableEdgesArgs,\n ): PluginApiReturn<ErasableEdgeRef[]>\n\n /**\n * Commit the erase for one edge. `DirectUnion` merges the two adjacent masses;\n * `DirectDelete` drops the single mass behind the boundary edge. Single undo entry.\n *\n * Pass an {@linkcode ErasableEdgeRef} from {@linkcode listErasableEdges}\n * unmodified. A stale ref (graph rebuilt by a prior mutation) or a `SplitAndUnion`\n * edge throws.\n *\n * @param edge - The {@linkcode ErasableEdgeRef} to erase, from {@linkcode listErasableEdges} unmodified\n * @returns `{ ok: true }` on success (the engine yields no survivor id today).\n * @throws when the ref is stale, its components are all erase-ineligible, or the\n * strategy is not committable via the scripted path.\n *\n * @examplePrompt Erase the edge between these two rooms so they merge\n * @examplePrompt Remove the shared boundary between the kitchen and the dining space\n * @examplePrompt Merge the two adjacent rooms by erasing their common edge\n * @examplePrompt Knock through the partition line between these spaces\n * @examplePrompt Erase this boundary edge from the plan\n *\n * # Example\n * ```ts\n * // Merge two adjacent rooms by erasing an internal edge they share\n * const edges = await snaptrude.design.erase.listErasableEdges({ strategies: [\"DirectUnion\"] })\n * if (edges.length > 0) {\n * const { ok } = await snaptrude.design.erase.edge(edges[0])\n * }\n * ```\n */\n public abstract edge(edge: ErasableEdgeRef): PluginApiReturn<PluginDesignEraseEdgeResult>\n}\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { ComponentHandle } from \"../../../handles\"\nimport { PluginDesignChangeResult } from \"../lock\"\n\n/**\n * Arguments for {@linkcode PluginDesignDeleteApi.entities}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `components` | {@linkcode ComponentHandle}`[]` | Entities to delete. Unknown/forged handles reject the whole call (fail-fast). |\n *\n * `.min(1)` is deliberately stricter than the shipped `PluginDesignLockArgs`\n * (which allows an empty array) — an empty delete is a caller error, not a no-op.\n *\n * TRANSPORT: positional args — validated host-side as `{ components }`.\n */\nexport const PluginDesignDeleteEntitiesArgs = z.object({\n components: z.array(ComponentHandle).min(1),\n})\nexport type PluginDesignDeleteEntitiesArgs = z.infer<typeof PluginDesignDeleteEntitiesArgs>\n\n/**\n * `snaptrude.design.delete.*` — **hard removal** of scene BIM entities.\n *\n * This is hard entity delete — distinct from `design.erase.edge` (a plan-level\n * adjacency-edge topology op) and `design.boolean.subtract` (a CSG geometry\n * delete). The constitution forbids `erase`/`clear`/`remove` as synonyms for\n * `delete`; these are three separate operations.\n *\n * TRANSPORT: positional args per method.\n */\nexport abstract class PluginDesignDeleteApi {\n constructor() {}\n\n /**\n * Delete one or more entities. Generic hard delete (backed by the same batched,\n * undoable path as `entity.space.delete`). Cascade is opinionated by the engine:\n * children are removed and linked-list neighbours are fixed up — not caller-tunable\n * in v1. Undoable — commits as a **single** undo entry.\n *\n * @param components - Entities to delete. Unknown/forged handles reject the whole call (fail-fast).\n * @returns The entities that were deleted, as {@linkcode ComponentHandle}`[]`\n * (echoed host-side from the resolved+deleted set — the engine returns no ids).\n * Deleted handles are **stale** afterwards: re-resolving one throws `HANDLE_INVALID`.\n * @throws If any supplied handle is unknown/forged (`HANDLE_INVALID`) — the whole\n * call rejects before anything is deleted (all-or-nothing resolution).\n *\n * @examplePrompt Delete the selected objects\n * @examplePrompt Remove these walls from the model\n * @examplePrompt Get rid of this mass entirely\n * @examplePrompt Delete all the furniture I picked\n * @examplePrompt Remove the door and window I just created\n *\n * # Example\n * ```ts\n * // Hard-delete every furniture item on storey 2 (a single undo entry)\n * const furniture = await snaptrude.design.query.listFurniture({ storeys: [2] })\n * if (furniture.length > 0) {\n * const { affected } = await snaptrude.design.delete.entities(furniture)\n * }\n * ```\n */\n public abstract entities(\n components: ComponentHandle[],\n ): PluginApiReturn<PluginDesignChangeResult>\n}\n","import * as z from \"zod\"\nimport { ComponentHandle } from \"../../handles\"\n\n/**\n * Shared `design.*` operation return records (LLD Part A.3).\n *\n * `PluginDesignChangeResult` (`{ affected }`) is NOT here — it already lives in\n * `./lock` and is reused verbatim by the transform/delete mutators.\n *\n * NOTE: `PluginMirrorAxis` currently lives in `./doors`; its relocation into this\n * shared module is deferred to the transform wave (avoids a doors edit + a\n * double-export while `design.transform` is unwired).\n */\n\n/**\n * Result of a CSG boolean op (`design.boolean.union/subtract/intersect`). Grounded\n * in the engine `Boolean3dOperation.resultComponents { toCreate; toDelete }`:\n * `created` are the result masses, `deleted` is every consumed input (for\n * `subtract` this includes BOTH the target AND the tools). Errors throw (RPC\n * rejects); no `Result<>` crosses the boundary.\n */\nexport const BooleanOutcome = z.object({\n created: z.array(ComponentHandle),\n deleted: z.array(ComponentHandle),\n})\nexport type BooleanOutcome = z.infer<typeof BooleanOutcome>\n\n/**\n * Result of `design.edit.offsetSplit` (migrated from `tools.offset`). `createdIds`\n * are the components the offset produced; `deletedIds` are those a split-style\n * offset removed. `offsetValue` is the engine's POST-clamp / post-sign applied\n * distance — the only way a caller learns the actually-applied clamped distance\n * (the shipped `tools.offset` result dropped it).\n */\nexport const OffsetSplitOutcome = z.object({\n createdIds: z.array(ComponentHandle),\n deletedIds: z.array(ComponentHandle),\n offsetValue: z.number(),\n})\nexport type OffsetSplitOutcome = z.infer<typeof OffsetSplitOutcome>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { ComponentHandle, Vec3Handle } from \"../../../handles\"\nimport { BooleanOutcome } from \"../shared\"\n\n/**\n * `snaptrude.design.boolean` — OpenCascade CSG on scene masses/spaces.\n *\n * Every method **commits** the operation as one undoable step (engine `run()`\n * queues create/delete/group/dimension commands, `execute()` runs them through\n * `CommandManager`) and returns the committed {@linkcode BooleanOutcome}. Failures\n * **throw** (RPC rejects) — no `Result<>` monad crosses the boundary.\n *\n * Eligibility (all inputs): a `Mass` that is a room OR a DEPARTMENT, has a brep, is\n * unlocked (mesh + bucket), visible, and NOT in a parametric-copy group; the whole\n * set must be all-planar OR all-non-planar; **≥2** components; all inputs share one\n * group or are ungrouped; inputs must be adjacent/overlapping.\n *\n * `design.boolean.subtract` is a **CSG geometry delete** — distinct from\n * `design.delete.entities` (hard entity removal) and `design.erase.edge`\n * (adjacency-edge topology op).\n *\n * TRANSPORT: positional args per method.\n */\nexport abstract class PluginDesignBooleanApi {\n constructor() {}\n\n /**\n * Fuse two or more masses into a single combined mass (`A ∪ B ∪ …`) — a boolean\n * (CSG) union that merges the adjacent or overlapping inputs into one solid,\n * committed as a single undoable step. Order-independent.\n * @param components - The ≥2 entities to fuse (order-independent)\n * @param options - Optional output offset — {@linkcode BooleanOptions}\n * @returns The committed CSG delta — {@linkcode BooleanOutcome}\n * @throws if inputs are ineligible, disjoint, non-manifold when joined, span\n * different groups, or the CSG yields no / invalid geometry.\n *\n * @examplePrompt Merge these two masses into one\n * @examplePrompt Union the selected volumes into a single mass\n * @examplePrompt Combine the overlapping rooms into one shape\n * @examplePrompt Join the tower and podium blocks together\n * @examplePrompt Fuse all the selected massing blocks into a single solid\n *\n * # Example\n * ```ts\n * // Fuse the overlapping massing blocks on the ground storey into one solid\n * const masses = await snaptrude.design.query.listMasses({ storeys: [1] })\n * const { created, deleted } = await snaptrude.design.boolean.union(masses)\n * console.log(\"created\", created.length, \"mass; consumed\", deleted.length)\n * ```\n */\n public abstract union(\n components: ComponentHandle[],\n options?: BooleanOptions,\n ): PluginApiReturn<BooleanOutcome>\n\n /**\n * Cut one or more tool masses out of a target mass (`target − ⋃tools`) — a\n * boolean (CSG) subtraction that carves the tools' volume out of the target and\n * commits the remainder as a single undoable step.\n *\n * ORDER-SENSITIVE: the host seeds `[target, ...tools]`; index 0 is the arg brep,\n * the rest are tool breps. `deleted` includes the target AND every tool;\n * `created` is the remainder mass(es).\n * @param target - The entity subtracted FROM (arg brep)\n * @param tools - The ≥1 entities subtracted (tool breps)\n * @param options - Optional output offset — {@linkcode BooleanOptions}\n * @returns The committed CSG delta — {@linkcode BooleanOutcome}\n * @throws as {@linkcode union}; a `NoResult` here carries the \"select the target\n * object first\" hint from the engine.\n *\n * @examplePrompt Cut this shape out of the bigger mass\n * @examplePrompt Subtract the cylinder from the building volume\n * @examplePrompt Punch an opening through this block using the small box\n * @examplePrompt Carve the courtyard volume out of the main massing\n * @examplePrompt Remove the overlapping part of mass B from mass A\n *\n * # Example\n * ```ts\n * // Order matters: the first arg is the target, the array holds the tools\n * const [building, courtyard] = await snaptrude.design.selection.get()\n * const { created, deleted } = await snaptrude.design.boolean.subtract(building, [courtyard])\n * // deleted includes the target AND every tool; created is the remainder\n * ```\n */\n public abstract subtract(\n target: ComponentHandle,\n tools: ComponentHandle[],\n options?: BooleanOptions,\n ): PluginApiReturn<BooleanOutcome>\n\n /**\n * Keep only the overlapping volume of exactly two masses (`A ∩ B`) — a boolean\n * (CSG) intersection that discards everything outside the shared region and\n * commits the overlap as a single undoable step. Order-independent.\n *\n * HARD constraint: **EXACTLY 2** components (schema `.length(2)`; the engine\n * also throws `MoreThan2ComponentsForIntersect` on >2).\n * @param components - **EXACTLY 2** entities to intersect (order-independent)\n * @param options - Optional output offset — {@linkcode BooleanOptions}\n * @returns The committed CSG delta — {@linkcode BooleanOutcome}\n * @throws as {@linkcode union}, plus `MoreThan2ComponentsForIntersect` on >2.\n *\n * @examplePrompt Keep only the part where these two masses overlap\n * @examplePrompt Intersect the two selected volumes\n * @examplePrompt Give me the common volume between the tower and the zoning envelope\n * @examplePrompt Trim this mass down to just its overlap with the other one\n *\n * # Example\n * ```ts\n * // Keep only the overlap of the tower and the zoning envelope (EXACTLY 2 inputs),\n * // shifting the result mass 10 units in x via the optional offset\n * const [tower, envelope] = await snaptrude.design.query.listMasses()\n * const offset = await snaptrude.core.math.vec3.new(10, 0, 0)\n * const { created } = await snaptrude.design.boolean.intersect([tower, envelope], { offset })\n * ```\n */\n public abstract intersect(\n components: ComponentHandle[],\n options?: BooleanOptions,\n ): PluginApiReturn<BooleanOutcome>\n}\n\n/**\n * Optional knobs shared by all boolean ops. The only safe one is a world-space\n * translation applied to the output mass(es) — maps to `Boolean3dOperation.offset`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `offset` | {@linkcode Vec3Handle} | Translation added to the created result mass(es) (default: none) |\n */\nexport const BooleanOptions = z.object({\n offset: Vec3Handle.optional(),\n})\nexport type BooleanOptions = z.infer<typeof BooleanOptions>\n\n/**\n * Arguments for {@linkcode PluginDesignBooleanApi.union}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `components` | {@linkcode ComponentHandle}`[]` | The ≥2 entities to fuse (order-independent) |\n * | `options` | {@linkcode BooleanOptions} | Optional output offset |\n */\nexport const PluginDesignBooleanUnionArgs = z.object({\n components: z.array(ComponentHandle).min(2),\n options: BooleanOptions.optional(),\n})\nexport type PluginDesignBooleanUnionArgs = z.infer<typeof PluginDesignBooleanUnionArgs>\n\n/**\n * Arguments for {@linkcode PluginDesignBooleanApi.subtract}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `target` | {@linkcode ComponentHandle} | The entity subtracted FROM (arg brep) |\n * | `tools` | {@linkcode ComponentHandle}`[]` | The ≥1 entities subtracted (tool breps) |\n * | `options` | {@linkcode BooleanOptions} | Optional output offset |\n */\nexport const PluginDesignBooleanSubtractArgs = z.object({\n target: ComponentHandle,\n tools: z.array(ComponentHandle).min(1),\n options: BooleanOptions.optional(),\n})\nexport type PluginDesignBooleanSubtractArgs = z.infer<typeof PluginDesignBooleanSubtractArgs>\n\n/**\n * Arguments for {@linkcode PluginDesignBooleanApi.intersect}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `components` | {@linkcode ComponentHandle}`[]` | **EXACTLY 2** entities to intersect (order-independent) |\n * | `options` | {@linkcode BooleanOptions} | Optional output offset |\n */\nexport const PluginDesignBooleanIntersectArgs = z.object({\n components: z.array(ComponentHandle).length(2),\n options: BooleanOptions.optional(),\n})\nexport type PluginDesignBooleanIntersectArgs = z.infer<typeof PluginDesignBooleanIntersectArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { ComponentHandle, Vec3Handle } from \"../../../handles\"\nimport { PluginDesignChangeResult } from \"../lock\"\n\n/**\n * `snaptrude.design.transform` — rigid transforms on scene entities.\n *\n * Migrated from the removed `tools.transform.*`. All ops are undoable and return\n * {@linkcode PluginDesignChangeResult} `{ affected }`; failures throw (RPC rejects).\n *\n * `mirror` / `getPosition` / `setPosition` (and `scale`, an engine gap) are NOT in\n * this surface yet — they are a later, non-migration pass.\n */\nexport abstract class PluginDesignTransformApi {\n constructor() {}\n\n /**\n * Translate entities by a **relative** displacement vector (added to the first\n * component's absolute position as the anchor). Undoable.\n *\n * @param components - Entities to move\n * @param displacement - Relative translation as a {@linkcode Vec3Handle}\n * @param options - `is2D`, `trackParentChange`\n * @returns {@linkcode PluginDesignChangeResult}\n *\n * @examplePrompt Move the selected room 5 metres to the right\n * @examplePrompt Shift these walls 3m along the x axis\n * @examplePrompt Nudge this space 500mm north\n * @examplePrompt Translate the furniture block by (10, 0, 5)\n * @examplePrompt Move these masses up one storey\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n * await snaptrude.design.transform.move([\"space-id\"], vec3.new(10, 0, 0))\n * ```\n */\n public abstract move(\n components: ComponentHandle[],\n displacement: Vec3Handle,\n options?: { is2D?: boolean; trackParentChange?: boolean },\n ): PluginApiReturn<PluginDesignChangeResult>\n\n /**\n * Rotate entities by a **signed angle in DEGREES**, anchored at the combined\n * bounding-box centre (positive = CCW about +Y). NOTE: unlike the removed\n * `tools.transform.rotate` (radians + caller pivot), this canonical form takes\n * DEGREES and has NO caller pivot — the pivot is always the bbox centre. Undoable.\n *\n * @param components - Entities to rotate\n * @param angleInDegrees - Signed rotation angle in degrees\n * @param options - `axis` (defaults to world +Y), `is2D`\n * @returns {@linkcode PluginDesignChangeResult}\n *\n * @examplePrompt Rotate the selected building 90 degrees\n * @examplePrompt Turn this room 45 degrees clockwise\n * @examplePrompt Spin the furniture block 180 degrees about its centre\n * @examplePrompt Rotate these masses 30 degrees around the vertical axis\n *\n * # Example\n * ```ts\n * await snaptrude.design.transform.rotate([\"space-id\"], 90)\n * ```\n */\n public abstract rotate(\n components: ComponentHandle[],\n angleInDegrees: number,\n options?: { axis?: Vec3Handle; is2D?: boolean },\n ): PluginApiReturn<PluginDesignChangeResult>\n}\n\n/**\n * Arguments for {@linkcode PluginDesignTransformApi.move} (options flattened).\n */\nexport const PluginDesignMoveArgs = z.object({\n components: z.array(ComponentHandle).min(1),\n displacement: Vec3Handle,\n is2D: z.boolean().optional(),\n trackParentChange: z.boolean().optional(),\n})\nexport type PluginDesignMoveArgs = z.infer<typeof PluginDesignMoveArgs>\n\n/**\n * Arguments for {@linkcode PluginDesignTransformApi.rotate} (options flattened).\n */\nexport const PluginDesignRotateArgs = z.object({\n components: z.array(ComponentHandle).min(1),\n angleInDegrees: z.number(),\n axis: Vec3Handle.optional(),\n is2D: z.boolean().optional(),\n})\nexport type PluginDesignRotateArgs = z.infer<typeof PluginDesignRotateArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { ComponentHandle, Vec3Handle } from \"../../../handles\"\nimport { OffsetSplitOutcome } from \"../shared\"\n\n/**\n * STAGED (LLD Wave 2) — abstract shell only. NOT yet wired into `PluginDesignApi`\n * and has no host implementation. `offsetSplit` migrates off `tools.offset` (adding\n * the previously-dropped `offsetValue` to the result).\n *\n * `snaptrude.design.edit` — non-create geometry edits (offset-split, and later\n * push-pull / topology edits). Undoable.\n *\n * TRANSPORT: positional args per method.\n */\nexport abstract class PluginDesignEditApi {\n constructor() {}\n\n /**\n * Offset the top profile of a component by a distance and split the face along\n * the offset curve. Positive distances offset outward, negative inward.\n * Single-component only (the engine rejects batches).\n * @param component - The component whose top profile is offset-split.\n * @param offsetDistance - Offset distance; positive = outward, negative = inward.\n * @param options - Optional settings: `profilePickPoint` picks the profile when ambiguous.\n * @returns {@linkcode OffsetSplitOutcome} `{ createdIds, deletedIds, offsetValue }`\n *\n * @examplePrompt Offset the top face of this mass inward by 2 metres and split it\n * @examplePrompt Create a 1m setback border on top of the selected mass\n * @examplePrompt Split the roof profile with a 500mm inward offset\n * @examplePrompt Offset-split the slab's top profile outward by 3 feet\n *\n * # Example\n * ```ts\n * // Offset the top profile inward by 2 units and split the face along it\n * const [mass] = await snaptrude.design.query.listMasses()\n * const { createdIds, offsetValue } = await snaptrude.design.edit.offsetSplit(mass, -2)\n * // offsetValue is the post-clamp distance the engine actually applied\n * ```\n */\n public abstract offsetSplit(\n component: ComponentHandle,\n offsetDistance: number,\n options?: { profilePickPoint?: Vec3Handle },\n ): PluginApiReturn<OffsetSplitOutcome>\n}\n\n// Positional target: offsetSplit(component, offsetDistance, options?)\nexport const PluginDesignOffsetSplitArgs = z.object({\n component: ComponentHandle,\n offsetDistance: z.number(),\n profilePickPoint: Vec3Handle.optional(),\n})\nexport type PluginDesignOffsetSplitArgs = z.infer<typeof PluginDesignOffsetSplitArgs>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../../types\"\nimport { ComponentHandle, ProfileHandle } from \"../../../handles\"\nimport {\n PluginSpaceType,\n PluginMassType,\n PluginDepartmentId,\n PluginAreaClass,\n PluginSpaceUpdateResult,\n} from \"../../entity/space\"\n\n/**\n * Sparse property updates for a space. Only provided fields change.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `room_type` | `string`? | Room label |\n * | `massType` | `PluginMassType`? | Mass type |\n * | `spaceType` | `PluginSpaceType`? | Space type |\n * | `areaClass` | `PluginAreaClass`? | Area class (NET/GROSS/EXCLUDED) |\n * | `departmentId` | `PluginDepartmentId`? | Department |\n */\nexport const PluginSpacePropertyUpdates = z.object({\n room_type: z.string().optional(),\n massType: PluginMassType.optional(),\n spaceType: PluginSpaceType.optional(),\n areaClass: PluginAreaClass.optional(),\n departmentId: PluginDepartmentId.optional(),\n})\nexport type PluginSpacePropertyUpdates = z.infer<typeof PluginSpacePropertyUpdates>\n\n/** Geometry replacement for a space — re-extrude a profile. */\nexport const PluginSpaceGeometryUpdate = z.object({\n profile: ProfileHandle,\n extrudeHeight: z.number(),\n})\nexport type PluginSpaceGeometryUpdate = z.infer<typeof PluginSpaceGeometryUpdate>\n\n/** One space to update via {@linkcode PluginDesignUpdateApi.spaces}. */\nexport const PluginUpdateSpaceItem = z.object({\n space: ComponentHandle,\n properties: PluginSpacePropertyUpdates.optional(),\n geometry: PluginSpaceGeometryUpdate.optional(),\n})\nexport type PluginUpdateSpaceItem = z.infer<typeof PluginUpdateSpaceItem>\n\n/**\n * `snaptrude.design.update` — edit existing scene entities (properties + geometry).\n *\n * Migrated from the removed `entity.space.{update, updateGeometryFromProfile, bulkUpdate}`.\n * Only provided fields change; each call is undoable. Failures throw (RPC rejects).\n */\nexport abstract class PluginDesignUpdateApi {\n constructor() {}\n\n /**\n * Update a single space (room) — change its properties (room label, space\n * type, mass type, area class, department) and/or replace its geometry by\n * re-extruding a profile to a new height. Sparse and undoable: only the\n * fields you provide change.\n *\n * @param space - The space to update\n * @param options - `properties` (sparse) and/or `geometry` ({ profile, extrudeHeight })\n * @returns the updated space's echoed {@linkcode PluginSpaceUpdateResult}\n *\n * @examplePrompt Rename this room to Office\n * @examplePrompt Change this space's room type to Meeting Room\n * @examplePrompt Set the height of this room to 3 metres\n * @examplePrompt Move this space into the Circulation department\n * @examplePrompt Exclude this room from the area calculations\n *\n * # Example\n * ```ts\n * await snaptrude.design.update.space(\"space-id\", { properties: { room_type: \"Office\" } })\n * ```\n */\n public abstract space(\n space: ComponentHandle,\n options: {\n properties?: PluginSpacePropertyUpdates\n geometry?: PluginSpaceGeometryUpdate\n },\n ): PluginApiReturn<PluginSpaceUpdateResult>\n\n /**\n * Update many spaces (rooms) in one undoable operation — the bulk form of\n * {@linkcode space}. Each item pairs a space with the sparse property\n * changes and/or geometry re-extrude to apply; every item is validated up\n * front, then all changes are applied as a single command.\n *\n * Migrated from `entity.space.bulkUpdate`.\n *\n * @param items - One {@linkcode PluginUpdateSpaceItem} per space\n * @returns one {@linkcode PluginSpaceUpdateResult} per item, in input order\n *\n * @examplePrompt Label all the selected rooms as Bedrooms\n * @examplePrompt Change the room type of these five spaces at once\n * @examplePrompt Set every room on this floor to a 3m height in one go\n * @examplePrompt Bulk-assign these spaces to the Service department\n * @examplePrompt Mark all of these rooms as excluded from area in one update\n *\n * # Example\n * ```ts\n * // Re-label every selected room and mark it NET area — one undoable bulk update\n * const rooms = await snaptrude.design.query.listSpaces({ isSelected: true })\n * const results = await snaptrude.design.update.spaces(\n * rooms.map((space) => ({\n * space,\n * properties: { room_type: \"Bedroom\", areaClass: \"NET\" },\n * })),\n * )\n * // One result per item, in input order\n * console.log(results.map((r) => r.spaceId))\n * ```\n */\n public abstract spaces(items: PluginUpdateSpaceItem[]): PluginApiReturn<PluginSpaceUpdateResult[]>\n}\n","import { PluginApiReturn } from \"../../types\"\nimport { ComponentHandle } from \"../../handles\"\nimport { PluginDesignCreateApi } from \"./create\"\nimport { PluginDesignQueryApi } from \"./query\"\nimport { PluginDesignSelectionApi } from \"./selection\"\nimport { PluginDesignDoorsApi } from \"./doors\"\nimport { PluginDesignWindowsApi } from \"./windows\"\nimport { PluginDesignFurnitureApi } from \"./furniture\"\nimport { PluginDesignMaterialsApi } from \"./materials\"\nimport { PluginDesignEraseApi } from \"./erase\"\nimport { PluginDesignDeleteApi } from \"./delete\"\nimport { PluginDesignBooleanApi } from \"./boolean\"\nimport { PluginDesignTransformApi } from \"./transform\"\nimport { PluginDesignEditApi } from \"./edit\"\nimport { PluginDesignUpdateApi } from \"./update\"\nimport { PluginDesignChangeResult } from \"./lock\"\n\n/**\n * `snaptrude.design.*` — author, query & edit BIM geometry.\n *\n * - {@linkcode PluginDesignApi.create} — new BIM entities\n * - {@linkcode PluginDesignApi.query} — read entities + their geometry\n * - {@linkcode PluginDesignApi.selection} — read/mutate the scene selection\n * - {@linkcode PluginDesignApi.doors} / {@linkcode PluginDesignApi.windows} — fenestration reads + edits\n * - {@linkcode PluginDesignApi.furniture} — furniture catalog reads\n * - {@linkcode PluginDesignApi.materials} — material library + assignment\n * - {@linkcode PluginDesignApi.boolean} — CSG boolean ops (union / subtract / intersect)\n * - {@linkcode PluginDesignApi.erase} — plan-level adjacency-edge erase (NOT hard delete)\n * - {@linkcode PluginDesignApi.delete} — hard entity removal\n * - {@linkcode PluginDesignApi.lock} / {@linkcode PluginDesignApi.unlock} / {@linkcode PluginDesignApi.isLocked} / {@linkcode PluginDesignApi.listLocked} — lock state (top-level design verbs, §2A.1)\n *\n * Transform and edit operation namespaces land here in later waves.\n */\nexport abstract class PluginDesignApi {\n /** Author new scene-committed BIM entities. See {@linkcode PluginDesignCreateApi}. */\n public abstract create: PluginDesignCreateApi\n /** Read scene entities and their geometry. See {@linkcode PluginDesignQueryApi}. */\n public abstract query: PluginDesignQueryApi\n /** Read/mutate the current selection. See {@linkcode PluginDesignSelectionApi}. */\n public abstract selection: PluginDesignSelectionApi\n /** Door-specific reads + edits. See {@linkcode PluginDesignDoorsApi}. */\n public abstract doors: PluginDesignDoorsApi\n /** Window-specific reads. See {@linkcode PluginDesignWindowsApi}. */\n public abstract windows: PluginDesignWindowsApi\n /** Furniture catalog reads. See {@linkcode PluginDesignFurnitureApi}. */\n public abstract furniture: PluginDesignFurnitureApi\n /** Material library + assignment. See {@linkcode PluginDesignMaterialsApi}. */\n public abstract materials: PluginDesignMaterialsApi\n /** Plan-level adjacency-edge erase (NOT hard delete). See {@linkcode PluginDesignEraseApi}. */\n public abstract erase: PluginDesignEraseApi\n /** Hard entity removal. See {@linkcode PluginDesignDeleteApi}. */\n public abstract delete: PluginDesignDeleteApi\n /** CSG boolean ops (union / subtract / intersect). See {@linkcode PluginDesignBooleanApi}. */\n public abstract boolean: PluginDesignBooleanApi\n /** Rigid transforms — move / rotate. See {@linkcode PluginDesignTransformApi}. */\n public abstract transform: PluginDesignTransformApi\n /** Non-create geometry edits — offset-split. See {@linkcode PluginDesignEditApi}. */\n public abstract edit: PluginDesignEditApi\n /** Update existing entities — properties + geometry. See {@linkcode PluginDesignUpdateApi}. */\n public abstract update: PluginDesignUpdateApi\n\n /**\n * Lock entities so they cannot be edited. Undoable. Cascades to void/door/window\n * children, stacked-wall companions, and terrain neighborhood; skips\n * active-group members.\n * @param components Entities to lock\n * @returns The affected entities (post-cascade)\n *\n * @examplePrompt Lock the selected walls so they can't be edited\n * @examplePrompt Freeze these masses so nobody moves them by accident\n * @examplePrompt Lock everything on the ground floor\n * @examplePrompt Protect this room from further changes\n *\n * # Example\n * ```ts\n * // Lock every wall on the ground storey\n * const walls = await snaptrude.design.query.listWalls({ storeys: [1] })\n * const { affected } = await snaptrude.design.lock(walls)\n * // affected is post-cascade: hosted doors/windows are included\n * ```\n */\n public abstract lock(components: ComponentHandle[]): PluginApiReturn<PluginDesignChangeResult>\n\n /**\n * Unlock previously locked entities so they can be edited again. Undoable.\n * Paired with {@linkcode PluginDesignApi.lock}.\n * @param components Entities to unlock\n * @returns The affected entities\n *\n * @examplePrompt Unlock the selected objects\n * @examplePrompt Make this locked wall editable again\n * @examplePrompt Unfreeze the masses I locked earlier\n * @examplePrompt Remove the lock from these doors\n *\n * # Example\n * ```ts\n * // Unlock everything that is explicitly locked\n * const locked = await snaptrude.design.listLocked()\n * const { affected } = await snaptrude.design.unlock(locked)\n * ```\n */\n public abstract unlock(components: ComponentHandle[]): PluginApiReturn<PluginDesignChangeResult>\n\n /**\n * Test whether an entity is locked (folds group + bucket lock unless `includeInherited: false`).\n * @param component The entity to test\n * @param includeInherited Fold group + bucket lock (default `true`); `false` reads the own flag only\n * @returns `true` if locked, otherwise `false`\n *\n * @examplePrompt Is this wall locked?\n * @examplePrompt Check whether the selected mass is locked or editable\n * @examplePrompt Why can't I move this object? Check if it is locked\n * @examplePrompt Tell me if this room is locked, counting locks inherited from its group\n *\n * # Example\n * ```ts\n * const [wall] = await snaptrude.design.query.listWalls()\n * const locked = await snaptrude.design.isLocked(wall)\n * // Own flag only — ignore locks inherited from the group / bucket\n * const ownLock = await snaptrude.design.isLocked(wall, false)\n * ```\n */\n public abstract isLocked(\n component: ComponentHandle,\n includeInherited?: boolean,\n ): PluginApiReturn<boolean>\n\n /**\n * List the explicitly-locked entities (excludes purely group/bucket-inherited locks).\n * @returns The locked entities as {@linkcode ComponentHandle}`[]`\n *\n * @examplePrompt Which objects in the model are locked?\n * @examplePrompt List all the locked entities in this project\n * @examplePrompt Show everything that has been locked\n * @examplePrompt Are there any locked walls or masses in the scene?\n *\n * # Example\n * ```ts\n * const locked = await snaptrude.design.listLocked()\n * console.log(locked.length, \"explicitly locked entities\")\n * ```\n */\n public abstract listLocked(): PluginApiReturn<ComponentHandle[]>\n\n constructor() {}\n}\n\nexport * from \"./create\"\nexport * from \"./query\"\nexport * from \"./selection\"\nexport * from \"./doors\"\nexport * from \"./windows\"\nexport * from \"./furniture\"\nexport * from \"./materials\"\nexport * from \"./lock\"\nexport * from \"./erase\"\nexport * from \"./delete\"\nexport * from \"./shared\"\nexport * from \"./boolean\"\nexport * from \"./transform\"\nexport * from \"./edit\"\nexport * from \"./update\"\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Buildable Envelope management — create and update parametric zoning envelopes.\n *\n * A **buildable envelope** is the regulated volume inside which a building may\n * be massed. The host owns envelope identity: {@linkcode PluginBuildableEnvelopeApi.create create}\n * mints a `buildableEnvelopeId` and returns it; {@linkcode PluginBuildableEnvelopeApi.update update}\n * requires that id to target the existing envelope.\n *\n * Accessed via `snaptrude.entity.buildableEnvelope`.\n */\nexport abstract class PluginBuildableEnvelopeApi {\n constructor() {}\n\n /**\n * Create a new parametric buildable envelope — the zoning-regulated volume a\n * building may occupy — generated from a site polygon, tiered setbacks, a\n * height or floor-count cap, and optional FAR and lot-coverage limits.\n *\n * @param sitePolygon - Site polygon vertices in `lengthUnit`; minimum 3 vertices.\n * @param lengthUnit - Unit used by all length fields (`\"ft\" | \"m\"`).\n * @param setbacks - Setback profile, ground tier first; minimum 1 tier.\n * @param verticalCap - Maximum height or floor count.\n * @param floorToFloor - Required floor-to-floor height in `lengthUnit`.\n * @param farRatio - Optional FAR value, positive when provided.\n * @param lotCoverageMaxPct - Optional lot coverage cap, `0..100`.\n * @returns A {@linkcode PluginBuildableEnvelopeCreateResult} with the\n * `buildableEnvelopeId` of the created envelope.\n * @throws If validation fails or generation produces no renderable geometry.\n *\n * @examplePrompt Create a buildable envelope for my site\n * @examplePrompt Generate the zoning envelope with 10ft front setbacks\n * @examplePrompt Show the maximum buildable volume with a 150ft height limit\n * @examplePrompt Model the allowable massing from the setback rules\n * @examplePrompt Create a zoning envelope capped at 12 floors with FAR 3\n *\n * # Example\n * ```ts\n * const { buildableEnvelopeId } = await snaptrude.entity.buildableEnvelope.create(\n * [\n * { x: 0, z: 0 },\n * { x: 100, z: 0 },\n * { x: 100, z: 80 },\n * { x: 0, z: 80 },\n * ],\n * \"ft\",\n * [\n * { aboveHeight: 0, front: 10, side: 5, rear: 10 },\n * { aboveHeight: 100, front: 20, side: 10, rear: 20 },\n * ],\n * { kind: \"max_height\", maxHeight: 150 },\n * 12,\n * )\n * ```\n */\n public abstract create(\n sitePolygon: PluginBuildableEnvelopePolygonVertex[],\n lengthUnit: \"ft\" | \"m\",\n setbacks: PluginBuildableEnvelopeSetbackTier[],\n verticalCap: PluginBuildableEnvelopeVerticalCap,\n floorToFloor: number,\n farRatio?: number,\n lotCoverageMaxPct?: number\n ): PluginApiReturn<PluginBuildableEnvelopeCreateResult>\n\n /**\n * Update an existing parametric buildable envelope — regenerate the zoning\n * volume from a revised site polygon, setbacks, vertical cap, or FAR and\n * lot-coverage limits, keeping the same envelope id.\n *\n * @param buildableEnvelopeId - Existing envelope ID to update; non-empty and\n * must match an existing envelope on the canvas.\n * @param sitePolygon - Site polygon vertices in `lengthUnit`; minimum 3 vertices.\n * @param lengthUnit - Unit used by all length fields (`\"ft\" | \"m\"`).\n * @param setbacks - Setback profile, ground tier first; minimum 1 tier.\n * @param verticalCap - Maximum height or floor count.\n * @param floorToFloor - Required floor-to-floor height in `lengthUnit`.\n * @param farRatio - Optional FAR value, positive when provided.\n * @param lotCoverageMaxPct - Optional lot coverage cap, `0..100`.\n * @returns A {@linkcode PluginBuildableEnvelopeUpdateResult} with the\n * `buildableEnvelopeId` of the updated envelope.\n * @throws If validation fails, the envelope does not exist, or generation\n * produces no renderable geometry.\n *\n * @examplePrompt Change the envelope's height limit to 175 feet\n * @examplePrompt Update the setbacks on the buildable envelope\n * @examplePrompt Regenerate the zoning envelope with a new site boundary\n * @examplePrompt Increase the FAR on the buildable volume\n * @examplePrompt Modify the envelope to allow 15 storeys instead\n *\n * # Example\n * ```ts\n * const { buildableEnvelopeId } = await snaptrude.entity.buildableEnvelope.update(\n * existingId,\n * [\n * { x: 0, z: 0 },\n * { x: 100, z: 0 },\n * { x: 100, z: 80 },\n * { x: 0, z: 80 },\n * ],\n * \"ft\",\n * [{ aboveHeight: 0, front: 10, side: 5, rear: 10 }],\n * { kind: \"max_height\", maxHeight: 175 },\n * 12,\n * )\n * ```\n */\n public abstract update(\n buildableEnvelopeId: string,\n sitePolygon: PluginBuildableEnvelopePolygonVertex[],\n lengthUnit: \"ft\" | \"m\",\n setbacks: PluginBuildableEnvelopeSetbackTier[],\n verticalCap: PluginBuildableEnvelopeVerticalCap,\n floorToFloor: number,\n farRatio?: number,\n lotCoverageMaxPct?: number\n ): PluginApiReturn<PluginBuildableEnvelopeUpdateResult>\n}\n\n/**\n * Site polygon vertex in the request `lengthUnit`.\n *\n * Vertices may be passed as `{x, z}` objects or `[x, z]` tuples. Numeric\n * values must be finite (no `NaN` or `±Infinity`).\n */\nexport const PluginBuildableEnvelopePolygonVertex = z.union([\n z.object({ x: z.number().finite(), z: z.number().finite() }).strict(),\n z.tuple([z.number().finite(), z.number().finite()]),\n])\n\nexport type PluginBuildableEnvelopePolygonVertex = z.infer<\n typeof PluginBuildableEnvelopePolygonVertex\n>\n\n/**\n * Vertical cap for a buildable envelope.\n *\n * Use exactly one shape:\n * - `{ kind: \"max_height\", maxHeight }`\n * - `{ kind: \"max_floors\", maxFloors }`\n *\n * Floor-to-floor height is not nested here; it is always supplied as the\n * top-level `floorToFloor` argument.\n */\nexport const PluginBuildableEnvelopeVerticalCap = z.discriminatedUnion(\"kind\", [\n z.object({\n kind: z.literal(\"max_height\"),\n maxHeight: z.number().finite().positive(),\n }).strict(),\n z.object({\n kind: z.literal(\"max_floors\"),\n maxFloors: z.number().finite().int().positive(),\n }).strict(),\n])\n\nexport type PluginBuildableEnvelopeVerticalCap = z.infer<\n typeof PluginBuildableEnvelopeVerticalCap\n>\n\n/**\n * One tier of a buildable envelope's setback profile.\n *\n * Tiers are ordered by `aboveHeight`. The first tier (index 0) must have\n * `aboveHeight: 0` and describes the ground footprint; each subsequent tier\n * describes the complete setback at a strictly greater height. Each tier\n * carries its own `front`, `side`, and `rear` values — there is no\n * inheritance from earlier tiers.\n *\n * All numeric values must be finite and nonnegative, in the request\n * `lengthUnit`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `aboveHeight` | `number` | Height at or above which this tier applies; the ground tier uses `0` |\n * | `front` | `number` | Front setback for this tier |\n * | `side` | `number` | Side setback for this tier |\n * | `rear` | `number` | Rear setback for this tier |\n */\nexport const PluginBuildableEnvelopeSetbackTier = z.object({\n aboveHeight: z.number().finite().nonnegative(),\n front: z.number().finite().nonnegative(),\n side: z.number().finite().nonnegative(),\n rear: z.number().finite().nonnegative(),\n}).strict()\n\nexport type PluginBuildableEnvelopeSetbackTier = z.infer<\n typeof PluginBuildableEnvelopeSetbackTier\n>\n\n// Enforces setback tier ordering invariants on the parsed args shape:\n// - setbacks[0].aboveHeight === 0\n// - aboveHeight strictly increasing thereafter\n// Length >= 1 is enforced earlier by z.array(...).min(1).\nfunction refineSetbackTiers(\n args: { setbacks: PluginBuildableEnvelopeSetbackTier[] },\n ctx: z.RefinementCtx\n): void {\n const tiers = args.setbacks\n if (tiers.length === 0) return\n if (tiers[0].aboveHeight !== 0) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"setbacks\", 0, \"aboveHeight\"],\n message: \"Ground tier required: setbacks[0].aboveHeight must be 0.\",\n })\n }\n for (let i = 1; i < tiers.length; i++) {\n if (!(tiers[i].aboveHeight > tiers[i - 1].aboveHeight)) {\n ctx.addIssue({\n code: z.ZodIssueCode.custom,\n path: [\"setbacks\", i, \"aboveHeight\"],\n message:\n \"Setback tiers must be ordered by strictly increasing aboveHeight.\",\n })\n }\n }\n}\n\n/**\n * Arguments for {@linkcode PluginBuildableEnvelopeApi.create}.\n *\n * Strict schema. The host owns identity — no `buildableEnvelopeId` is accepted\n * on create; the id is minted by the host and returned in\n * {@linkcode PluginBuildableEnvelopeCreateResult}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sitePolygon` | {@linkcode PluginBuildableEnvelopePolygonVertex}`[]` | Site polygon vertices in `lengthUnit`; minimum 3 vertices |\n * | `lengthUnit` | `\"ft\" \\| \"m\"` | Unit used by all length fields |\n * | `setbacks` | {@linkcode PluginBuildableEnvelopeSetbackTier}`[]` | Setback profile, ground tier first; minimum 1 tier |\n * | `verticalCap` | {@linkcode PluginBuildableEnvelopeVerticalCap} | Maximum height or floor count |\n * | `floorToFloor` | `number` | Required floor-to-floor height in `lengthUnit` |\n * | `farRatio` | `number?` | Optional FAR value, positive when provided |\n * | `lotCoverageMaxPct` | `number?` | Optional lot coverage cap, `0..100` |\n */\nexport const PluginBuildableEnvelopeCreateArgs = z\n .object({\n sitePolygon: z.array(PluginBuildableEnvelopePolygonVertex).min(3),\n lengthUnit: z.union([z.literal(\"ft\"), z.literal(\"m\")]),\n setbacks: z.array(PluginBuildableEnvelopeSetbackTier).min(1),\n verticalCap: PluginBuildableEnvelopeVerticalCap,\n floorToFloor: z.number().finite().positive(),\n farRatio: z.number().finite().positive().optional(),\n lotCoverageMaxPct: z.number().finite().min(0).max(100).optional(),\n })\n .strict()\n .superRefine(refineSetbackTiers)\n\nexport type PluginBuildableEnvelopeCreateArgs = z.infer<\n typeof PluginBuildableEnvelopeCreateArgs\n>\n\n/**\n * Result of {@linkcode PluginBuildableEnvelopeApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildableEnvelopeId` | `string` | Non-empty unique ID of the created buildable envelope |\n */\nexport const PluginBuildableEnvelopeCreateResult = z.object({\n buildableEnvelopeId: z.string().min(1),\n}).strict()\n\nexport type PluginBuildableEnvelopeCreateResult = z.infer<\n typeof PluginBuildableEnvelopeCreateResult\n>\n\n/**\n * Arguments for {@linkcode PluginBuildableEnvelopeApi.update}.\n *\n * Strict schema. `buildableEnvelopeId` is required and identifies the prior\n * envelope on the canvas to update.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildableEnvelopeId` | `string` | Existing envelope ID to update; non-empty |\n * | `sitePolygon` | {@linkcode PluginBuildableEnvelopePolygonVertex}`[]` | Site polygon vertices in `lengthUnit`; minimum 3 vertices |\n * | `lengthUnit` | `\"ft\" \\| \"m\"` | Unit used by all length fields |\n * | `setbacks` | {@linkcode PluginBuildableEnvelopeSetbackTier}`[]` | Setback profile, ground tier first; minimum 1 tier |\n * | `verticalCap` | {@linkcode PluginBuildableEnvelopeVerticalCap} | Maximum height or floor count |\n * | `floorToFloor` | `number` | Required floor-to-floor height in `lengthUnit` |\n * | `farRatio` | `number?` | Optional FAR value, positive when provided |\n * | `lotCoverageMaxPct` | `number?` | Optional lot coverage cap, `0..100` |\n */\nexport const PluginBuildableEnvelopeUpdateArgs = z\n .object({\n buildableEnvelopeId: z.string().min(1),\n sitePolygon: z.array(PluginBuildableEnvelopePolygonVertex).min(3),\n lengthUnit: z.union([z.literal(\"ft\"), z.literal(\"m\")]),\n setbacks: z.array(PluginBuildableEnvelopeSetbackTier).min(1),\n verticalCap: PluginBuildableEnvelopeVerticalCap,\n floorToFloor: z.number().finite().positive(),\n farRatio: z.number().finite().positive().optional(),\n lotCoverageMaxPct: z.number().finite().min(0).max(100).optional(),\n })\n .strict()\n .superRefine(refineSetbackTiers)\n\nexport type PluginBuildableEnvelopeUpdateArgs = z.infer<\n typeof PluginBuildableEnvelopeUpdateArgs\n>\n\n/**\n * Result of {@linkcode PluginBuildableEnvelopeApi.update}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `buildableEnvelopeId` | `string` | Non-empty unique ID of the updated buildable envelope |\n */\nexport const PluginBuildableEnvelopeUpdateResult = z.object({\n buildableEnvelopeId: z.string().min(1),\n}).strict()\n\nexport type PluginBuildableEnvelopeUpdateResult = z.infer<\n typeof PluginBuildableEnvelopeUpdateResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\nimport { ProfileHandle, CurveHandle } from \"../../handles\"\n\n/**\n * Reference line management — create, query, and delete reference lines.\n *\n * A **reference line** is a 2D guide line (or arc) in the Snaptrude scene,\n * typically used for grid lines and alignment guides. Reference lines\n * carry properties such as grid tags, labels, and line styles.\n *\n * All methods are **host API calls** that return Promises and support\n * undo/redo via Snaptrude's command system.\n *\n * Accessed via `snaptrude.entity.referenceLine`.\n */\nexport abstract class PluginReferenceLineApi {\n constructor() {}\n\n /**\n * Create multiple reference lines from a profile.\n *\n * Each curve in the given {@linkcode ProfileHandle} becomes\n * a separate reference line. Uses `ReferenceLineConstructor.createFromProfile`\n * internally.\n *\n * @param profile - A {@linkcode ProfileHandle} whose curves define the\n * reference lines to create\n * @returns A {@linkcode PluginReferenceLineCreateMultiResult} with the\n * `referenceLineIds` of the created reference lines\n * @throws If reference line creation fails\n *\n * @examplePrompt Draw grid lines across the site\n * @examplePrompt Create reference lines from these curves\n * @examplePrompt Add alignment guides along the building edge\n * @examplePrompt Set up a structural grid using guide lines\n * @examplePrompt Turn this profile into reference lines\n *\n * # Example\n * ```ts\n * const { vec3 } = snaptrude.core.math\n *\n * const start = await vec3.new(0, 0, 0)\n * const mid = await vec3.new(10, 0, 0)\n * const end = await vec3.new(10, 0, 10)\n * const l1 = await snaptrude.core.geom.create.line(start, mid)\n * const l2 = await snaptrude.core.geom.create.line(mid, end)\n * const profile = await snaptrude.core.geom.create.profileFromCurves([l1, l2])\n *\n * const { referenceLineIds } = await snaptrude.entity.referenceLine.createMulti(profile)\n * ```\n */\n public abstract createMulti(\n profile: ProfileHandle\n ): PluginApiReturn<PluginReferenceLineCreateMultiResult>\n\n /**\n * Get properties of a reference line by its ID.\n *\n * Only the properties listed in `properties` are returned — unlisted\n * properties will be `undefined` in the result.\n *\n * @param referenceLineId - The unique reference line ID\n * @param properties - Array of property names to retrieve. See\n * {@linkcode PluginReferenceLineGetProperty}.\n * @returns A partial {@linkcode PluginReferenceLineGetResult} containing only the\n * requested properties\n * @throws If the reference line does not exist\n *\n * @examplePrompt Get the curve geometry of this reference line\n * @examplePrompt Where does this grid line run?\n * @examplePrompt Read the geometry of a guide line by its id\n * @examplePrompt Look up the curve of the selected reference line\n *\n * # Example\n * ```ts\n * const result = await snaptrude.entity.referenceLine.get(\"some-ref-line-id\", [\"curve\"])\n * // result.curve is an opaque CurveHandle; a dedicated curve read API for its\n * // coordinates is exposed separately via `snaptrude.core.geom.curve`.\n * ```\n */\n public abstract get(\n referenceLineId: string,\n properties: z.infer<typeof PluginReferenceLineGetProperty>[]\n ): PluginApiReturn<PluginReferenceLineGetResult>\n\n /**\n * Get the IDs of all reference lines in the current project.\n *\n * Returns every reference line across all stories.\n * Use the returned IDs with {@linkcode PluginReferenceLineApi.get} to query\n * individual reference line properties.\n *\n * @returns A {@linkcode PluginReferenceLineGetAllResult} with a\n * `referenceLineIds` array\n *\n * @examplePrompt How many grid lines are in the project?\n * @examplePrompt List all the reference lines in my model\n * @examplePrompt Show every guide line in the file\n * @examplePrompt Do I have any reference lines in this project?\n *\n * # Example\n * ```ts\n * const { referenceLineIds } = await snaptrude.entity.referenceLine.getAll()\n * console.log(`Project has ${referenceLineIds.length} reference lines`)\n * ```\n */\n public abstract getAll(): PluginApiReturn<PluginReferenceLineGetAllResult>\n\n /**\n * Delete a reference line by its ID.\n *\n * Permanently removes the reference line and its associated mesh from\n * the scene. This operation is undoable via Snaptrude's command system.\n *\n * @param referenceLineId - The unique reference line ID to delete\n * @throws If the reference line does not exist\n *\n * @examplePrompt Delete this reference line\n * @examplePrompt Remove the grid line I just drew\n * @examplePrompt Get rid of the alignment guide on the left\n * @examplePrompt Erase a reference line by its id\n *\n * # Example\n * ```ts\n * await snaptrude.entity.referenceLine.delete(\"some-ref-line-id\")\n * ```\n */\n public abstract delete(\n referenceLineId: string\n ): PluginApiReturn<PluginReferenceLineDeleteResult>\n}\n\n/**\n * Arguments for {@linkcode PluginReferenceLineApi.createMulti}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `profile` | {@linkcode ProfileHandle} | Profile handle whose curves define reference lines |\n */\nexport const PluginReferenceLineCreateMultiArgs = z.object({\n profile: ProfileHandle,\n})\n\nexport type PluginReferenceLineCreateMultiArgs = z.infer<typeof PluginReferenceLineCreateMultiArgs>\n\n/**\n * Result of {@linkcode PluginReferenceLineApi.createMulti}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `referenceLineIds` | `string[]` | IDs of the created reference lines |\n */\nexport const PluginReferenceLineCreateMultiResult = z.object({\n referenceLineIds: z.array(z.string()),\n})\n\nexport type PluginReferenceLineCreateMultiResult = z.infer<typeof PluginReferenceLineCreateMultiResult>\n\n/**\n * Available properties that can be queried on a reference line.\n *\n * | Value | Return Type | Description |\n * |---|---|---|\n * | `\"curve\"` | {@linkcode CurveHandle} | The curve geometry of the reference line, as an opaque handle |\n */\nexport const PluginReferenceLineGetProperty = z.enum([\n \"curve\",\n])\n\n/**\n * Arguments for {@linkcode PluginReferenceLineApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `referenceLineId` | `string` | The reference line ID to query |\n * | `properties` | {@linkcode PluginReferenceLineGetProperty}`[]` | Properties to retrieve |\n */\nexport const PluginReferenceLineGetArgs = z.object({\n referenceLineId: z.string(),\n properties: z.array(PluginReferenceLineGetProperty),\n})\n\nexport type PluginReferenceLineGetArgs = z.infer<typeof PluginReferenceLineGetArgs>\n\n/**\n * Result of {@linkcode PluginReferenceLineApi.get}.\n *\n * A partial object — only the properties that were requested in\n * {@linkcode PluginReferenceLineGetArgs.properties} will be present.\n */\nexport const PluginReferenceLineGetResult = z\n .object({\n curve: CurveHandle,\n })\n .partial()\n\nexport type PluginReferenceLineGetResult = z.infer<typeof PluginReferenceLineGetResult>\n\n/**\n * Result of {@linkcode PluginReferenceLineApi.getAll}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `referenceLineIds` | `string[]` | IDs of all reference lines in the project |\n */\nexport const PluginReferenceLineGetAllResult = z.object({\n referenceLineIds: z.array(z.string()),\n})\n\nexport type PluginReferenceLineGetAllResult = z.infer<typeof PluginReferenceLineGetAllResult>\n\n/**\n * Arguments for {@linkcode PluginReferenceLineApi.delete}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `referenceLineId` | `string` | The reference line ID to delete |\n */\nexport const PluginReferenceLineDeleteArgs = z.object({\n referenceLineId: z.string(),\n})\n\nexport type PluginReferenceLineDeleteArgs = z.infer<typeof PluginReferenceLineDeleteArgs>\n\n/** Result type for {@linkcode PluginReferenceLineApi.delete} — returns nothing on success. */\nexport type PluginReferenceLineDeleteResult = void\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Story (floor/storey) management.\n *\n * A story represents a building floor in the Snaptrude project. Stories\n * are identified by their integer **story value** (e.g. `1` for ground\n * floor, `2` for first floor, `-1` for a basement).\n *\n * All methods are **host API calls** that return Promises and support\n * undo/redo via Snaptrude's command system.\n *\n * Accessed via `snaptrude.entity.story`.\n */\nexport abstract class PluginStoryApi {\n constructor() {}\n\n /**\n * Get properties of a story by its storey number.\n *\n * Only the properties listed in `properties`\n * are returned — unlisted properties will be `undefined` in the result.\n *\n * @param storyValue - Integer storey number\n * (e.g. `1` for ground floor, `2` for first floor, `-1` for basement)\n * @param properties - Array of property names\n * to retrieve. See {@linkcode PluginStoryGetProperty} for available values.\n * @returns A partial {@linkcode PluginStoryGetResult} containing only the requested properties\n * @throws If the story with the given value does not exist\n *\n * @examplePrompt What is the height of the ground floor?\n * @examplePrompt How many rooms are on the second storey?\n * @examplePrompt Get the total floor area of level 3\n * @examplePrompt Is the first floor hidden in the viewport?\n * @examplePrompt Show me the name and height of story 2\n *\n * # Example\n * ```ts\n * const info = await snaptrude.entity.story.get(1, [\"height\", \"name\", \"spacesCount\"])\n * console.log(info.name, info.height, info.spacesCount)\n * ```\n */\n public abstract get(\n storyValue: number,\n properties: PluginStoryGetProperty[],\n ): PluginApiReturn<PluginStoryGetResult>\n\n /**\n * Get all stories in the current project.\n *\n * Returns basic identification data for every storey. Stories are sorted\n * from **top to bottom** (highest story value first).\n *\n * @returns A {@linkcode PluginStoryGetAllResult} with a `stories` array,\n * each entry containing `value`, `id`, and `name`\n *\n * @examplePrompt How many floors does this building have?\n * @examplePrompt List all the storeys in the project\n * @examplePrompt Show me every level with its name\n * @examplePrompt Which stories exist in this model?\n *\n * # Example\n * ```ts\n * const { stories } = await snaptrude.entity.story.getAll()\n * for (const s of stories) {\n * console.log(`Story ${s.value}: ${s.name} (id: ${s.id})`)\n * }\n * ```\n */\n public abstract getAll(): PluginApiReturn<PluginStoryGetAllResult>\n\n /**\n * Create a new story (floor) in the project.\n *\n * The new story is inserted at the position specified by\n * `storyValue`. This operation is undoable.\n *\n * @param storyValue - Integer storey number\n * to create (e.g. `3` to add a third floor)\n * @param height - Optional height in Babylon\n * units. If omitted, the project's default storey height is used.\n * @returns A {@linkcode PluginStoryCreateResult} with `storyId` and `storyValue`\n * @throws If a story with the given value already exists or creation fails\n *\n * @examplePrompt Add a third floor to the building\n * @examplePrompt Create a new storey above the second floor\n * @examplePrompt Add a basement level to this project\n * @examplePrompt Insert a new level with a custom floor height\n * @examplePrompt Add another floor on top of the building\n *\n * # Example\n * ```ts\n * // Create a new third floor with custom height\n * const { storyId } = await snaptrude.entity.story.create(3, 4.5)\n * ```\n */\n public abstract create(\n storyValue: number,\n height?: number,\n ): PluginApiReturn<PluginStoryCreateResult>\n\n /**\n * Update a story's height.\n *\n * Changes the floor-to-floor height of the specified story. This\n * operation is undoable.\n *\n * @param storyValue - Integer storey number\n * identifying the story to update\n * @param height - New height value in Babylon\n * units\n * @returns A {@linkcode PluginStoryUpdateResult} with the updated `storyValue` and `height`\n * @throws If the story does not exist or the update fails\n *\n * @examplePrompt Change the ground floor height to 3.5 metres\n * @examplePrompt Make the second storey taller\n * @examplePrompt Set the floor-to-floor height of level 1\n * @examplePrompt Increase the height of the third floor\n *\n * # Example\n * ```ts\n * // Set ground floor height to 5 Babylon units\n * const result = await snaptrude.entity.story.update(1, 5)\n * ```\n */\n public abstract update(\n storyValue: number,\n height: number,\n ): PluginApiReturn<PluginStoryUpdateResult>\n}\n\n/**\n * Available properties that can be queried on a story.\n *\n * | Value | Type | Description |\n * |---|---|---|\n * | `\"value\"` | `number` | The integer storey number |\n * | `\"id\"` | `string` | Unique story identifier |\n * | `\"name\"` | `string` | Display name of the story |\n * | `\"height\"` | `number` | Floor-to-floor height in Babylon units |\n * | `\"base\"` | `number` | Base elevation in Babylon units |\n * | `\"hidden\"` | `boolean` | Whether the story is hidden in the viewport |\n * | `\"spacesCount\"` | `number` | Number of spaces on this story |\n * | `\"totalArea\"` | `number` | Total floor area of this story |\n */\nexport const PluginStoryGetProperty = z.enum([\n \"value\",\n \"id\",\n \"name\",\n \"height\",\n \"base\",\n \"hidden\",\n \"spacesCount\",\n \"totalArea\",\n])\n\nexport type PluginStoryGetProperty = z.infer<typeof PluginStoryGetProperty>\n\n/**\n * Arguments for {@linkcode PluginStoryApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storyValue` | `number` (int) | The storey number to query |\n * | `properties` | {@linkcode PluginStoryGetProperty}`[]` | Properties to retrieve |\n */\nexport const PluginStoryGetArgs = z.object({\n storyValue: z.number().int(),\n properties: z.array(PluginStoryGetProperty),\n})\n\nexport type PluginStoryGetArgs = z.infer<typeof PluginStoryGetArgs>\n\n/**\n * Result of {@linkcode PluginStoryApi.get}.\n *\n * A partial object — only the properties that were requested in\n * {@linkcode PluginStoryGetArgs.properties} will be present.\n */\nexport const PluginStoryGetResult = z\n .object({\n value: z.number(),\n id: z.string(),\n name: z.string(),\n height: z.number(),\n base: z.number(),\n hidden: z.boolean(),\n spacesCount: z.number(),\n totalArea: z.number(),\n })\n .partial()\n\nexport type PluginStoryGetResult = z.infer<typeof PluginStoryGetResult>\n\n/**\n * Result of {@linkcode PluginStoryApi.getAll}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `stories` | `Array<{ value, id, name }>` | All stories, sorted top to bottom |\n */\nexport const PluginStoryGetAllResult = z.object({\n stories: z.array(\n z.object({\n value: z.number(),\n id: z.string(),\n name: z.string(),\n })\n ),\n})\n\nexport type PluginStoryGetAllResult = z.infer<typeof PluginStoryGetAllResult>\n\n/**\n * Arguments for {@linkcode PluginStoryApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storyValue` | `number` (int) | The storey number for the new story |\n * | `height` | `number?` | Optional height in Babylon units |\n */\nexport const PluginStoryCreateArgs = z.object({\n storyValue: z.number().int(),\n height: z.number().optional(),\n})\n\nexport type PluginStoryCreateArgs = z.infer<typeof PluginStoryCreateArgs>\n\n/**\n * Result of {@linkcode PluginStoryApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storyId` | `string` | Unique ID of the created story |\n * | `storyValue` | `number` | The storey number of the created story |\n */\nexport const PluginStoryCreateResult = z.object({\n storyId: z.string(),\n storyValue: z.number(),\n})\n\nexport type PluginStoryCreateResult = z.infer<typeof PluginStoryCreateResult>\n\n/**\n * Arguments for {@linkcode PluginStoryApi.update}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storyValue` | `number` (int) | Storey number of the story to update |\n * | `height` | `number` | New height in Babylon units |\n */\nexport const PluginStoryUpdateArgs = z.object({\n storyValue: z.number().int(),\n height: z.number(),\n})\n\nexport type PluginStoryUpdateArgs = z.infer<typeof PluginStoryUpdateArgs>\n\n/**\n * Result of {@linkcode PluginStoryApi.update}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `storyValue` | `number` | The storey number of the updated story |\n * | `height` | `number` | The new height after the update |\n */\nexport const PluginStoryUpdateResult = z.object({\n storyValue: z.number(),\n height: z.number(),\n})\n\nexport type PluginStoryUpdateResult = z.infer<typeof PluginStoryUpdateResult>\n","import { PluginBuildableEnvelopeApi } from \"./buildableEnvelope\"\nimport { PluginReferenceLineApi } from \"./referenceLine\"\nimport { PluginStoryApi } from \"./story\"\n\n/**\n * CRUD operations on Snaptrude building entities.\n *\n * - {@linkcode PluginEntityApi.story} — Create, query, and update stories (floors)\n * - {@linkcode PluginEntityApi.referenceLine} — Create, query, and delete reference lines\n * - {@linkcode PluginEntityApi.buildableEnvelope} — Create or update parametric buildable envelopes\n *\n * Space operations moved to `design.create.spaces` / `design.update.*` /\n * `design.query.*` / `design.delete.entities` (the `entity.space` API was removed);\n * `./space` still exports the shared space value types.\n */\nexport abstract class PluginEntityApi {\n /** Story (floor/storey) operations. See {@linkcode PluginStoryApi}. */\n public abstract story: PluginStoryApi\n /** Reference line operations. See {@linkcode PluginReferenceLineApi}. */\n public abstract referenceLine: PluginReferenceLineApi\n /** Buildable Envelope operations. See {@linkcode PluginBuildableEnvelopeApi}. */\n public abstract buildableEnvelope: PluginBuildableEnvelopeApi\n\n constructor() {}\n}\n\nexport * from \"./buildableEnvelope\"\nexport * from \"./referenceLine\"\nexport * from \"./space\"\nexport * from \"./story\"\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\nimport { PluginAreaUnit } from \"./metrics\"\nimport { ComponentHandle } from \"../../handles\"\n\n/**\n * Program departments — read the department groupings of the active program.\n *\n * In program mode a **department** is a named, colored grouping of spaces with an\n * optional area **target**. This is the program-planning view of departments\n * (their identity, color, and target area); the underlying space geometry is read\n * and edited through the geometry namespaces, not here.\n *\n * All methods are reads: they return plain records and never throw for a missing\n * department (`get` returns `null`, `list` returns `[]`).\n *\n * Accessed via `snaptrude.program.departments`.\n */\nexport abstract class PluginProgramDepartmentsApi {\n constructor() {}\n\n /**\n * List the departments in the active program.\n *\n * Returns every department — well-known (Default, Site, …) and user-created —\n * with its identity, color, and area target (when one has been set).\n *\n * @returns A {@linkcode PluginProgramDepartmentsListResult} with a `departments`\n * array (empty when the project has none).\n *\n * @examplePrompt List all the departments in my program\n * @examplePrompt What program groups do I have and what are their target areas?\n * @examplePrompt Show every department with its colour\n * @examplePrompt Get the area target for each department\n * @examplePrompt How many departments are in this project?\n *\n * # Example\n * ```ts\n * const { units, departments } = await snaptrude.program.departments.list()\n * for (const d of departments) console.log(d.name, d.color, d.targetArea, units)\n * ```\n */\n public abstract list(): PluginApiReturn<PluginProgramDepartmentsListResult>\n\n /**\n * Get a single department by id.\n *\n * @param departmentId - The id of the department to read.\n * @returns The matching {@linkcode PluginProgramDepartment}, or `null` if no\n * department has that id.\n *\n * @examplePrompt Get the department with id dep_123\n * @examplePrompt Look up a single department by its id\n * @examplePrompt What is the target area of this department id?\n *\n * # Example\n * ```ts\n * const dept = await snaptrude.program.departments.get(\"dep_123\")\n * if (dept) console.log(dept.name, dept.targetArea)\n * ```\n */\n public abstract get(\n departmentId: string,\n ): PluginApiReturn<PluginProgramDepartmentsGetResult>\n\n /**\n * Create a new department in the active program.\n *\n * Adds a named, colored program grouping. The new department starts empty —\n * put spaces in it with {@linkcode PluginProgramDepartmentsApi.assign}, and set\n * its area goal with {@linkcode PluginProgramDepartmentsApi.setTargetArea}.\n *\n * @param name - Display name of the new department.\n * @param color - CSS hex color string (e.g. `\"#b5e1dc\"`).\n * @returns The new department's id (read the full record back with\n * {@linkcode PluginProgramDepartmentsApi.get}).\n * @throws If the department could not be created.\n *\n * @examplePrompt Create a department called Bedrooms in light blue\n * @examplePrompt Add a new program group named Circulation with color #cccccc\n * @examplePrompt Make a Classrooms department\n * @examplePrompt Set up a Lobby department in the program\n *\n * # Example\n * ```ts\n * const { departmentId } = await snaptrude.program.departments.create(\"Bedrooms\", \"#b5e1dc\")\n * ```\n */\n public abstract create(\n name: string,\n color: string,\n ): PluginApiReturn<PluginProgramDepartmentsCreateResult>\n\n /**\n * Update a department's name and/or color.\n *\n * A **sparse** update: omitted fields are left unchanged. Use\n * {@linkcode PluginProgramDepartmentsApi.setTargetArea} to change the area\n * target (not this method).\n *\n * @param departmentId - The id of the department to update.\n * @param options - Any of `name`, `color`; omitted fields are left unchanged.\n * @returns The updated {@linkcode PluginProgramDepartment} (with the response\n * `units` for its `targetArea`).\n * @throws If no department has the given id.\n *\n * @examplePrompt Rename the Bedrooms department to Suites\n * @examplePrompt Change the Circulation department colour to #ff8800\n * @examplePrompt Recolour department dep_123\n * @examplePrompt Update the Lobby department's display name\n *\n * # Example\n * ```ts\n * const dept = await snaptrude.program.departments.update(\"dep_123\", { name: \"Suites\" })\n * ```\n */\n public abstract update(\n departmentId: string,\n options?: { name?: string; color?: string },\n ): PluginApiReturn<PluginProgramDepartmentsUpdateResult>\n\n /**\n * Assign one or more spaces to a department.\n *\n * Moves each space into the given department — an undoable membership change.\n * A space belongs to exactly one department, so assigning re-homes it from any\n * previous one. Paired with {@linkcode PluginProgramDepartmentsApi.unassign}.\n *\n * @param departmentId - The department to assign the spaces to.\n * @param spaceIds - The ids of the spaces to move into the department (at\n * least one).\n * @returns The department and the space ids that were assigned.\n * @throws If the department does not exist or a space id is invalid.\n *\n * @examplePrompt Assign the selected rooms to the Bedrooms department\n * @examplePrompt Put spaces 12 and 13 in the Circulation department\n * @examplePrompt Move this space into the Lobby department\n * @examplePrompt Add the kitchen spaces to the Service department\n *\n * # Example\n * ```ts\n * await snaptrude.program.departments.assign(\"dep_123\", [\"sp_1\", \"sp_2\"])\n * ```\n */\n public abstract assign(\n departmentId: string,\n spaceIds: ComponentHandle[],\n ): PluginApiReturn<PluginProgramDepartmentsAssignResult>\n\n /**\n * Remove one or more spaces from their department.\n *\n * Returns each space to the **Default** department — there is no \"no\n * department\" state, so unassigning means reassigning to Default. Paired with\n * {@linkcode PluginProgramDepartmentsApi.assign}.\n *\n * @param spaceIds - The ids of the spaces to remove from their current\n * department (at least one).\n * @returns The space ids that were returned to Default.\n * @throws If a space id is invalid.\n *\n * @examplePrompt Remove the selected rooms from their department\n * @examplePrompt Unassign space sp_1 from any department\n * @examplePrompt Clear the department on these spaces\n * @examplePrompt Take the kitchen out of the Service department\n *\n * # Example\n * ```ts\n * await snaptrude.program.departments.unassign([\"sp_1\"])\n * ```\n */\n public abstract unassign(\n spaceIds: ComponentHandle[],\n ): PluginApiReturn<PluginProgramDepartmentsUnassignResult>\n\n /**\n * Set a department's target area.\n *\n * The goal the program metrics compare allocated area against (see\n * {@linkcode PluginProgramMetricsApi}). Pass `units` to say what unit\n * `targetArea` is in; it defaults to the project's area units. Read the target\n * back from {@linkcode PluginProgramDepartmentsApi.get} (`targetArea`).\n *\n * @param departmentId - The id of the department whose target to set.\n * @param targetArea - The target area, in `units`.\n * @param units - Unit of `targetArea` (defaults to the project's area units).\n * @returns The updated {@linkcode PluginProgramDepartment} with its `units`.\n * @throws If no department has the given id.\n *\n * @examplePrompt Set the Bedrooms department target area to 2000 sqft\n * @examplePrompt Give the Circulation department a 500 sqm area target\n * @examplePrompt Target 1500 square feet for the Classrooms department\n * @examplePrompt Update the area goal for department dep_123\n *\n * # Example\n * ```ts\n * await snaptrude.program.departments.setTargetArea(\"dep_123\", 2000, \"ft2\")\n * ```\n */\n public abstract setTargetArea(\n departmentId: string,\n targetArea: number,\n units?: PluginAreaUnit,\n ): PluginApiReturn<PluginProgramDepartmentsSetTargetAreaResult>\n\n /**\n * Delete a department.\n *\n * Any spaces still assigned to it are returned to the **Default** department\n * (no space is left orphaned). The reserved departments (Default, Site,\n * Envelope, Core) cannot be deleted.\n *\n * @param departmentId - The id of the department to delete.\n * @returns The id of the deleted department and the spaces that were reassigned\n * to Default.\n * @throws If no department has the given id, or it is a reserved department.\n *\n * @examplePrompt Delete the Bedrooms department\n * @examplePrompt Remove the empty Circulation department\n * @examplePrompt Delete department dep_123 and move its rooms to Default\n *\n * # Example\n * ```ts\n * await snaptrude.program.departments.delete(\"dep_123\")\n * ```\n */\n public delete?: (\n departmentId: string,\n ) => PluginApiReturn<PluginProgramDepartmentsDeleteResult>\n}\n\n/**\n * A department in the active program. Its `targetArea` is in the enclosing\n * response's `units` (see the area-units convention in\n * {@linkcode PluginAreaUnit}).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Unique department id |\n * | `name` | `string` | Display name |\n * | `color` | `string` | CSS hex color string (e.g. `\"#b5e1dc\"`) |\n * | `targetArea` | `number \\| null` | Target area in the response's `units`, or `null` if no target is set |\n */\nexport const PluginProgramDepartment = z.object({\n id: z.string(),\n name: z.string(),\n color: z.string(),\n targetArea: z.number().nullable(),\n})\nexport type PluginProgramDepartment = z.infer<typeof PluginProgramDepartment>\n\n/**\n * Result of {@linkcode PluginProgramDepartmentsApi.list}. Per the area-units\n * convention, `units` sits on this response envelope (not on each record).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `units` | `\"ft2\" \\| \"m2\"` | The unit every `targetArea` below is reported in |\n * | `departments` | {@linkcode PluginProgramDepartment}`[]` | All departments in the active program |\n */\nexport const PluginProgramDepartmentsListResult = z.object({\n units: PluginAreaUnit,\n departments: z.array(PluginProgramDepartment),\n})\nexport type PluginProgramDepartmentsListResult = z.infer<\n typeof PluginProgramDepartmentsListResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramDepartmentsApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `departmentId` | `string` | The id of the department to read |\n */\nexport const PluginProgramDepartmentsGetArgs = z.object({\n departmentId: z.string(),\n})\nexport type PluginProgramDepartmentsGetArgs = z.infer<\n typeof PluginProgramDepartmentsGetArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramDepartmentsApi.get} — the department, or\n * `null` when no department has the given id. This is a bare `.get` record, so\n * per the area-units convention `units` is carried on the record itself.\n */\nexport const PluginProgramDepartmentsGetResult = PluginProgramDepartment.extend(\n {\n units: PluginAreaUnit,\n },\n).nullable()\nexport type PluginProgramDepartmentsGetResult = z.infer<\n typeof PluginProgramDepartmentsGetResult\n>\n\n/**\n * A department record with its area `units` — the shape returned by the\n * single-record department writes (`update`, `setTargetArea`). Per the\n * area-units convention, a bare record carries `units` on itself.\n */\nexport const PluginProgramDepartmentRecord = PluginProgramDepartment.extend({\n units: PluginAreaUnit,\n})\nexport type PluginProgramDepartmentRecord = z.infer<\n typeof PluginProgramDepartmentRecord\n>\n\n/**\n * Arguments for {@linkcode PluginProgramDepartmentsApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string` | Display name of the new department |\n * | `color` | `string` | CSS hex color string (e.g. `\"#b5e1dc\"`) |\n */\nexport const PluginProgramDepartmentsCreateArgs = z.object({\n name: z.string(),\n color: z.string(),\n})\nexport type PluginProgramDepartmentsCreateArgs = z.infer<\n typeof PluginProgramDepartmentsCreateArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramDepartmentsApi.create} — the id of the\n * newly created department.\n */\nexport const PluginProgramDepartmentsCreateResult = z.object({\n departmentId: z.string(),\n})\nexport type PluginProgramDepartmentsCreateResult = z.infer<\n typeof PluginProgramDepartmentsCreateResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramDepartmentsApi.update}. Sparse — only\n * the provided fields are changed.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `departmentId` | `string` | The id of the department to update |\n * | `name` | `string \\| undefined` | New display name (unchanged if omitted) |\n * | `color` | `string \\| undefined` | New CSS hex color (unchanged if omitted) |\n */\nexport const PluginProgramDepartmentsUpdateArgs = z.object({\n departmentId: z.string(),\n name: z.string().optional(),\n color: z.string().optional(),\n})\nexport type PluginProgramDepartmentsUpdateArgs = z.infer<\n typeof PluginProgramDepartmentsUpdateArgs\n>\n\n/** Result of {@linkcode PluginProgramDepartmentsApi.update} — the updated record. */\nexport const PluginProgramDepartmentsUpdateResult =\n PluginProgramDepartmentRecord\nexport type PluginProgramDepartmentsUpdateResult = z.infer<\n typeof PluginProgramDepartmentsUpdateResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramDepartmentsApi.assign}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `departmentId` | `string` | The department to assign the spaces to |\n * | `spaceIds` | `ComponentHandle[]` | The ids of the spaces to move into the department |\n */\nexport const PluginProgramDepartmentsAssignArgs = z.object({\n departmentId: z.string(),\n spaceIds: z.array(ComponentHandle).min(1),\n})\nexport type PluginProgramDepartmentsAssignArgs = z.infer<\n typeof PluginProgramDepartmentsAssignArgs\n>\n\n/** Result of {@linkcode PluginProgramDepartmentsApi.assign}. */\nexport const PluginProgramDepartmentsAssignResult = z.object({\n departmentId: z.string(),\n spaceIds: z.array(ComponentHandle),\n})\nexport type PluginProgramDepartmentsAssignResult = z.infer<\n typeof PluginProgramDepartmentsAssignResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramDepartmentsApi.unassign}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceIds` | `ComponentHandle[]` | The ids of the spaces to return to the Default department |\n */\nexport const PluginProgramDepartmentsUnassignArgs = z.object({\n spaceIds: z.array(ComponentHandle).min(1),\n})\nexport type PluginProgramDepartmentsUnassignArgs = z.infer<\n typeof PluginProgramDepartmentsUnassignArgs\n>\n\n/** Result of {@linkcode PluginProgramDepartmentsApi.unassign}. */\nexport const PluginProgramDepartmentsUnassignResult = z.object({\n spaceIds: z.array(ComponentHandle),\n})\nexport type PluginProgramDepartmentsUnassignResult = z.infer<\n typeof PluginProgramDepartmentsUnassignResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramDepartmentsApi.setTargetArea}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `departmentId` | `string` | The id of the department whose target to set |\n * | `targetArea` | `number` | The target area, in `units` |\n * | `units` | `\"ft2\" \\| \"m2\" \\| undefined` | Unit of `targetArea` (defaults to the project's area units) |\n */\nexport const PluginProgramDepartmentsSetTargetAreaArgs = z.object({\n departmentId: z.string(),\n targetArea: z.number(),\n units: PluginAreaUnit.optional(),\n})\nexport type PluginProgramDepartmentsSetTargetAreaArgs = z.infer<\n typeof PluginProgramDepartmentsSetTargetAreaArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramDepartmentsApi.setTargetArea} — the updated\n * department record with its `units`.\n */\nexport const PluginProgramDepartmentsSetTargetAreaResult =\n PluginProgramDepartmentRecord\nexport type PluginProgramDepartmentsSetTargetAreaResult = z.infer<\n typeof PluginProgramDepartmentsSetTargetAreaResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramDepartmentsApi.delete}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `departmentId` | `string` | The id of the department to delete |\n */\nexport const PluginProgramDepartmentsDeleteArgs = z.object({\n departmentId: z.string(),\n})\nexport type PluginProgramDepartmentsDeleteArgs = z.infer<\n typeof PluginProgramDepartmentsDeleteArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramDepartmentsApi.delete}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `departmentId` | `string` | The id of the deleted department |\n * | `reassignedSpaceIds` | `ComponentHandle[]` | Spaces that were returned to the Default department |\n */\nexport const PluginProgramDepartmentsDeleteResult = z.object({\n departmentId: z.string(),\n reassignedSpaceIds: z.array(ComponentHandle),\n})\nexport type PluginProgramDepartmentsDeleteResult = z.infer<\n typeof PluginProgramDepartmentsDeleteResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Program metrics — the area-program summary of the active project.\n *\n * Aggregate planning numbers: total target versus allocated area, plus a\n * per-department breakdown. This is the program-mode \"am I hitting my area\n * targets?\" read; per-entity geometry measurements (a single space's area,\n * volume, bounding box) live under the geometry namespaces, not here.\n *\n * Every area is reported in the summary's `units` (ft² or m²). This is a read:\n * it never throws and returns an empty breakdown with zero totals when the\n * project has no program.\n *\n * Accessed via `snaptrude.program.metrics`.\n */\nexport abstract class PluginProgramMetricsApi {\n constructor() {}\n\n /**\n * Get the area-program summary for the active project.\n *\n * @returns A {@linkcode PluginProgramMetricsSummary} with project-level totals\n * and a per-department area breakdown.\n *\n * @examplePrompt How much area have I allocated versus my targets?\n * @examplePrompt Give me the program area summary\n * @examplePrompt Which departments are over or under their target area?\n * @examplePrompt What's the total built area in the program?\n * @examplePrompt Show the area breakdown per department\n * @examplePrompt Am I within my area program?\n *\n * # Example\n * ```ts\n * const m = await snaptrude.program.metrics.get()\n * console.log(`${m.totalAllocatedArea} / ${m.totalTargetArea} ${m.units}`)\n * console.log(\"unassigned:\", m.unassignedArea)\n * for (const d of m.departments) {\n * console.log(d.name, d.allocatedArea, d.targetArea)\n * }\n * ```\n */\n public abstract get(): PluginApiReturn<PluginProgramMetricsSummary>\n}\n\n/**\n * The unit areas are reported in: square feet (`\"ft2\"`) or square metres (`\"m2\"`).\n *\n * **Area-units convention (applies to every area-returning method).** A result\n * carries exactly one `units` field, at the **top level of the value the method\n * returns**: on the response **envelope** for `list`/multi/composite results, and\n * on the **record itself** only for a single `.get` that returns a bare record.\n * Inner/leaf records never repeat it.\n */\nexport const PluginAreaUnit = z.enum([\"ft2\", \"m2\"])\nexport type PluginAreaUnit = z.infer<typeof PluginAreaUnit>\n\n/**\n * Per-department area figures within the program summary. Areas are in the\n * enclosing {@linkcode PluginProgramMetricsSummary}'s `units`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `departmentId` | `string` | Department id |\n * | `name` | `string` | Department name |\n * | `targetArea` | `number \\| null` | Target area in project units, or `null` if no target is set |\n * | `allocatedArea` | `number` | Area currently allocated to this department, in project units |\n */\nexport const PluginProgramDepartmentMetric = z.object({\n departmentId: z.string(),\n name: z.string(),\n targetArea: z.number().nullable(),\n allocatedArea: z.number(),\n})\nexport type PluginProgramDepartmentMetric = z.infer<\n typeof PluginProgramDepartmentMetric\n>\n\n/**\n * Result of {@linkcode PluginProgramMetricsApi.get}.\n *\n * Reconciliation invariant: `totalAllocatedArea === unassignedArea` plus the sum\n * of every `departments[].allocatedArea`. `totalTargetArea` is the sum of every\n * `departments[].targetArea` (a `null` target counts as 0); unassigned area has\n * no target. Every area is in `units`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `units` | `\"ft2\" \\| \"m2\"` | The unit every area in this summary is reported in |\n * | `totalTargetArea` | `number` | Sum of all department target areas |\n * | `totalAllocatedArea` | `number` | Total allocated area = departments + `unassignedArea` |\n * | `unassignedArea` | `number` | Allocated area not attributed to any listed department (site/unassigned) — the delta that reconciles the total |\n * | `departments` | {@linkcode PluginProgramDepartmentMetric}`[]` | Per-department area breakdown |\n */\nexport const PluginProgramMetricsSummary = z\n .object({\n units: PluginAreaUnit,\n totalTargetArea: z.number(),\n totalAllocatedArea: z.number(),\n unassignedArea: z.number(),\n departments: z.array(PluginProgramDepartmentMetric),\n })\n .refine(\n (s) => {\n const summed =\n s.unassignedArea +\n s.departments.reduce((acc, d) => acc + d.allocatedArea, 0)\n // Reconciliation tolerance: 0.01 absolute or 0.01% relative, for float drift.\n const tolerance = Math.max(0.01, Math.abs(s.totalAllocatedArea) * 1e-4)\n return Math.abs(s.totalAllocatedArea - summed) <= tolerance\n },\n {\n message:\n \"totalAllocatedArea must equal unassignedArea + the sum of departments[].allocatedArea\",\n },\n )\nexport type PluginProgramMetricsSummary = z.infer<\n typeof PluginProgramMetricsSummary\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Program adjacency — the proximity relationships between departments or\n * spaces.\n *\n * Adjacency is stage one of the product's space-planning workflow (compute →\n * arrange → pack): the AI service scores which program elements need to be\n * near each other, and the geometry contributes physical contact. Cell values:\n *\n * | Value | Meaning |\n * |---|---|\n * | `2` | Direct — adjacency required |\n * | `1` | Indirect — nearby preferred, or physical contact |\n * | `-1` | Restricted — must NOT be adjacent |\n * | `0` | No relationship — or adjacency was never computed |\n *\n * Zeros are ambiguous **by design** (the engine cannot distinguish \"no\n * relationship\" from \"never computed\"): call\n * {@linkcode PluginProgramAdjacencyApi.compute} first when you need fresh\n * data. Persisted matrices auto-hydrate on scene load, so warm reads are the\n * common case. The arrange/pack stages of the workflow live in\n * {@linkcode PluginProgramLayoutApi} (`program.layout`).\n *\n * Accessed via `snaptrude.program.adjacency`.\n */\nexport abstract class PluginProgramAdjacencyApi {\n constructor() {}\n\n /**\n * Read the adjacency matrix at the department or space level.\n *\n * Returns a square `matrix` whose rows/columns are aligned to `ids`\n * (component ids). Pass `ids` to read a sub-matrix in that order; omit it to\n * get every eligible element at that level. Cell values:\n *\n * | Value | Meaning |\n * |---|---|\n * | `2` | Direct — adjacency required |\n * | `1` | Indirect — nearby preferred, or physical contact |\n * | `-1` | Restricted — must NOT be adjacent |\n * | `0` | No relationship — or adjacency was never computed |\n *\n * Zeros are ambiguous by design — call\n * {@linkcode PluginProgramAdjacencyApi.compute} first for fresh data\n * (persisted matrices auto-hydrate on scene load, so warm reads are the\n * common case). Space-level relationships are computed within a storey:\n * cross-storey pairs always read `0`. At the `department` level the result\n * also carries `departmentIds`, a parallel array joining each row to the\n * department entity ids returned by `program.departments.list` (the row\n * `ids` are department-mass component ids, not department entity ids).\n *\n * @param level - Read the `\"department\"` or `\"space\"` matrix.\n * @param ids - Component ids to read a sub-matrix for, in this order\n * (defaults to every eligible element at the level).\n * @returns A {@linkcode PluginProgramAdjacencyGetMatrixResult} with `ids`,\n * the square `matrix`, and (at department level) `departmentIds`.\n * @throws If an id is unknown or does not match the requested level.\n *\n * @examplePrompt Get the space adjacency matrix\n * @examplePrompt Which departments must be adjacent?\n * @examplePrompt Show the adjacency relationships between departments\n * @examplePrompt Read the adjacency matrix for these spaces\n * @examplePrompt Which rooms are restricted from being next to each other?\n *\n * # Example\n * ```ts\n * const { ids, matrix } = await snaptrude.program.adjacency.getMatrix(\"department\")\n * ```\n */\n public abstract getMatrix(\n level: PluginAdjacencyLevel,\n ids?: string[],\n ): PluginApiReturn<PluginProgramAdjacencyGetMatrixResult>\n\n /**\n * Compute (or refresh) the adjacency data for the project.\n *\n * Runs the AI adjacency precompute and persists the result; a no-op when\n * the stored data is already fresh. A real run takes **~2s at minimum**\n * (engine pacing) plus the AI service round-trip. This is a write (it\n * mutates and persists project analysis data), so it is blocked when plugin\n * writes are disabled.\n *\n * @returns A {@linkcode PluginProgramAdjacencyComputeResult} —\n * `{ success: true }` when the data is fresh or the run completed;\n * `{ success: false, error }` when the AI service could not be reached.\n *\n * @examplePrompt Refresh adjacency analysis\n * @examplePrompt Compute the adjacency matrix for this project\n * @examplePrompt Recalculate which departments should be adjacent\n *\n * # Example\n * ```ts\n * const { success } = await snaptrude.program.adjacency.compute()\n * if (success) {\n * const data = await snaptrude.program.adjacency.getMatrix(\"space\")\n * }\n * ```\n */\n public abstract compute(): PluginApiReturn<PluginProgramAdjacencyComputeResult>\n}\n\n/**\n * The level an adjacency matrix is read at.\n *\n * | Value | Description |\n * |---|---|\n * | `\"department\"` | One row/column per department mass |\n * | `\"space\"` | One row/column per space (within a storey) |\n */\nexport const PluginAdjacencyLevel = z.enum([\"department\", \"space\"])\nexport type PluginAdjacencyLevel = z.infer<typeof PluginAdjacencyLevel>\n\n/**\n * Arguments for {@linkcode PluginProgramAdjacencyApi.getMatrix}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `level` | {@linkcode PluginAdjacencyLevel} | Read the `\"department\"` or `\"space\"` matrix |\n * | `ids` | `string[] \\| undefined` | Component ids to read a sub-matrix for, in this order (defaults to every eligible element at the level) |\n */\nexport const PluginProgramAdjacencyGetMatrixArgs = z.object({\n level: PluginAdjacencyLevel,\n ids: z.array(z.string()).optional(),\n})\nexport type PluginProgramAdjacencyGetMatrixArgs = z.infer<\n typeof PluginProgramAdjacencyGetMatrixArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramAdjacencyApi.getMatrix}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `ids` | `string[]` | Component ids, in matrix row/column order |\n * | `departmentIds` | `(string \\| null)[] \\| undefined` | Department level only: parallel to `ids`, the department entity id each row belongs to (joinable against `program.departments.list`), `null` when unassigned |\n * | `matrix` | `number[][]` | Square matrix aligned to `ids`; values in `{-1, 0, 1, 2}` |\n */\nexport const PluginProgramAdjacencyGetMatrixResult = z.object({\n ids: z.array(z.string()),\n departmentIds: z.array(z.string().nullable()).optional(),\n matrix: z.array(z.array(z.number())),\n})\nexport type PluginProgramAdjacencyGetMatrixResult = z.infer<\n typeof PluginProgramAdjacencyGetMatrixResult\n>\n\n/**\n * Result of {@linkcode PluginProgramAdjacencyApi.compute}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `success` | `boolean` | `true` when the data is fresh or the run completed |\n * | `error` | `string \\| undefined` | Failure reason when `success` is `false` |\n */\nexport const PluginProgramAdjacencyComputeResult = z.object({\n success: z.boolean(),\n error: z.string().optional(),\n})\nexport type PluginProgramAdjacencyComputeResult = z.infer<\n typeof PluginProgramAdjacencyComputeResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Program layout — arrange and pack spaces inside the envelope.\n *\n * These wrap the product's **Arrange in envelope** / **Pack in envelope**\n * tools (engine: `Planner.pack_arrange` in the react host) — stages two and\n * three of the space-planning workflow that starts with\n * {@linkcode PluginProgramAdjacencyApi} (`program.adjacency`).\n *\n * _(Authored ahead — both methods are optional until the host lands them in\n * the next increment, and are kept out of the discovery manifest until then.)_\n *\n * Accessed via `snaptrude.program.layout`.\n */\nexport abstract class PluginProgramLayoutApi {\n constructor() {}\n\n /**\n * Arrange the spaces inside the envelope using the computed adjacency data.\n * _(Authored ahead — optional until the host lands.)_\n *\n * @examplePrompt Arrange the rooms in the envelope\n * @examplePrompt Lay out the departments inside the building envelope\n * @examplePrompt Auto-arrange the program spaces\n *\n * # Example\n * ```ts\n * const { success, error } = await snaptrude.program.layout.arrange()\n * if (!success) console.log(\"Arrange failed:\", error)\n * ```\n */\n public arrange?: () => PluginApiReturn<PluginProgramLayoutRunResult>\n\n /**\n * Pack the spaces into the envelope (a tighter fit than arrange).\n * _(Authored ahead — optional until the host lands.)_\n *\n * @examplePrompt Pack the rooms into the envelope\n * @examplePrompt Fit the program spaces tightly into the building\n * @examplePrompt Run pack-in-envelope on this storey\n *\n * # Example\n * ```ts\n * const { success, error } = await snaptrude.program.layout.pack()\n * if (!success) console.log(\"Pack failed:\", error)\n * ```\n */\n public pack?: () => PluginApiReturn<PluginProgramLayoutRunResult>\n}\n\n/**\n * Result of {@linkcode PluginProgramLayoutApi.arrange} /\n * {@linkcode PluginProgramLayoutApi.pack}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `success` | `boolean` | Whether the layout run completed |\n * | `error` | `string \\| undefined` | Failure reason when `success` is `false` |\n */\nexport const PluginProgramLayoutRunResult = z.object({\n success: z.boolean(),\n error: z.string().optional(),\n})\nexport type PluginProgramLayoutRunResult = z.infer<\n typeof PluginProgramLayoutRunResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\nimport { PluginAreaUnit } from \"./metrics\"\n\n/**\n * Program spreadsheet — read a building's program/takeoff data and render, build,\n * and export report sheets from it. The surface spans two levels:\n *\n * - **High-level renders** — {@linkcode PluginProgramSpreadsheetApi.render} (rows +\n * columns → a formatted, titled table) and its dataset specializations\n * {@linkcode PluginProgramSpreadsheetApi.renderTakeoff} /\n * {@linkcode PluginProgramSpreadsheetApi.renderProgram} (the host pulls the\n * dataset). Authors think \"render my takeoff to a sheet\".\n * - **Low-level construction** — for authors who need fine control:\n * {@linkcode PluginProgramSpreadsheetApi.createSheet},\n * {@linkcode PluginProgramSpreadsheetApi.setValues},\n * {@linkcode PluginProgramSpreadsheetApi.setFormulas},\n * {@linkcode PluginProgramSpreadsheetApi.setStyles},\n * {@linkcode PluginProgramSpreadsheetApi.mergeCells},\n * {@linkcode PluginProgramSpreadsheetApi.addConditionalFormatting},\n * {@linkcode PluginProgramSpreadsheetApi.recalculate}, and\n * {@linkcode PluginProgramSpreadsheetApi.transaction} (atomic, undoable batch).\n *\n * Plus dataset reads ({@linkcode PluginProgramSpreadsheetApi.getProgram} /\n * {@linkcode PluginProgramSpreadsheetApi.getTakeoff} — the data the render* methods\n * draw), sheet reads ({@linkcode PluginProgramSpreadsheetApi.listSheets} /\n * {@linkcode PluginProgramSpreadsheetApi.getSheetData}), charts + emphasis\n * ({@linkcode PluginProgramSpreadsheetApi.addChart} /\n * {@linkcode PluginProgramSpreadsheetApi.highlightCells}), workbook file export\n * ({@linkcode PluginProgramSpreadsheetApi.export}), reusable\n * {@linkcode PluginProgramSpreadsheetApi.templates}, live\n * {@linkcode PluginProgramSpreadsheetApi.bindings}, a sandboxed script escape hatch\n * ({@linkcode PluginProgramSpreadsheetApi.runScript}), an audit log\n * ({@linkcode PluginProgramSpreadsheetApi.getAuditLog}), and a liveness\n * {@linkcode PluginProgramSpreadsheetApi.ping}. `addTable` is intentionally not\n * exposed — `render` composes header + rows + table in one call.\n *\n * **Verb note (naming authority; rows pending merge into constitution §4 by its owner).**\n * Existing §4 verbs used as-is: `get`, `list`, `set` (bulk cell/format writes;\n * read back via {@linkcode PluginProgramSpreadsheetApi.getSheetData}), `create`,\n * `add` (charts, conditional formats), `apply` (templates), `export`, and\n * `transaction` (the sanctioned atomic-batch verb), plus the ratified `render` and\n * `highlight` program domain verbs ◆. New program-domain verbs ratified here ◆:\n * `recalculate` (recompute the workbook's formula results — distinct from\n * `refresh`), `merge` ({@linkcode PluginProgramSpreadsheetApi.mergeCells} spans a\n * cell range — a spreadsheet-domain verb, explicitly NOT the CSG-solid `union`\n * fold), `refresh` ({@linkcode PluginProgramSpreadsheetBindingsApi.refresh}\n * re-pulls a binding's live source — distinct from `recalculate`), `run`\n * ({@linkcode PluginProgramSpreadsheetApi.runScript} executes a sandboxed script),\n * and `ping` (a meta liveness probe). Renames for compliance: the host's `save` →\n * `templates.create`; `getRecentEntries` → `getAuditLog`.\n *\n * Accessed via `snaptrude.program.spreadsheet`.\n */\nexport abstract class PluginProgramSpreadsheetApi {\n constructor() {}\n\n /**\n * Reusable sheet templates — capture a sheet's layout as a named template and\n * re-apply it to another sheet. See {@linkcode PluginProgramSpreadsheetTemplatesApi}.\n */\n public abstract templates: PluginProgramSpreadsheetTemplatesApi\n\n /**\n * Live data bindings — bind a program dataset to a sheet range and refresh it\n * on demand. See {@linkcode PluginProgramSpreadsheetBindingsApi}.\n */\n public abstract bindings: PluginProgramSpreadsheetBindingsApi\n\n /**\n * Render a titled, formatted table onto a named sheet (create-or-replace).\n *\n * The intent-level replacement for the raw cell-write sequence: it writes the\n * header + rows, applies per-column format/alignment, optionally wraps the\n * block in a table, freezes the header, and appends a totals row. This is the\n * generic table render; the `render*` family is reserved to also carry\n * dataset-specific renders (`renderTakeoff`, `renderProgram`) once their\n * argument shapes are ratified.\n *\n * @param sheetName - Target sheet name.\n * @param columns - Column definitions, at least one (see\n * {@linkcode PluginSpreadsheetColumn}).\n * @param rows - Row objects keyed by column `key`.\n * @param options - Optional `title`, `startCell` (default `\"A1\"`), `whenExists`\n * (default `\"replace\"`), `asTable` (default `true`), `freezeHeader` (default\n * `true`), and `totals` row.\n * @returns A {@linkcode PluginProgramSpreadsheetRenderResult} with the written\n * ranges and counts.\n * @throws If `columns` is empty, the target sheet exists and `whenExists` is\n * `\"error\"`, or a cell address is invalid.\n *\n * @examplePrompt Render my takeoff as a table on a sheet\n * @examplePrompt Write the area schedule to a spreadsheet with totals\n * @examplePrompt Put the department breakdown on a sheet called \"Program\"\n * @examplePrompt Output this data as a formatted table with a header\n * @examplePrompt Create a report sheet from these rows and columns\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.render(\n * \"Program\",\n * [\n * { key: \"name\", header: \"Department\" },\n * { key: \"area\", header: \"Area\", format: \"0.00\", align: \"right\" },\n * ],\n * [{ name: \"FOH\", area: 120.5 }],\n * { totals: [{ column: \"area\", fn: \"sum\", label: \"Total\" }] },\n * )\n * ```\n */\n public abstract render(\n sheetName: string,\n columns: PluginSpreadsheetColumn[],\n rows: Record<string, PluginSpreadsheetCell>[],\n options?: {\n title?: string\n startCell?: string\n whenExists?: \"replace\" | \"error\"\n asTable?: boolean\n freezeHeader?: boolean\n totals?: PluginSpreadsheetTotal[]\n },\n ): PluginApiReturn<PluginProgramSpreadsheetRenderResult>\n\n /**\n * Render the quantity/material takeoff onto a sheet.\n *\n * A specialization of the render* family: the **host pulls and projects the\n * current takeoff dataset itself** — the plugin supplies only the target\n * `sheetName`, an optional `title`, and an optional `filter`; there is **no\n * data argument**. Returns the same rendered-artifact record as\n * {@linkcode PluginProgramSpreadsheetApi.render}.\n * _(Authored ahead — optional via the `spreadsheet?` mount until the host\n * round-trip is live.)_\n *\n * @param options - Optional `sheetName`, `title`, and `filter` (a\n * {@linkcode PluginProgramSpreadsheetRenderDatasetArgs}).\n * @returns A {@linkcode PluginProgramSpreadsheetRenderResult} with the written\n * ranges and counts.\n * @throws If the takeoff cannot be rendered.\n *\n * @examplePrompt Render the takeoff onto a sheet\n * @examplePrompt Put the quantity takeoff on a spreadsheet\n * @examplePrompt Generate the takeoff schedule sheet titled Takeoff\n * @examplePrompt Render the material takeoff filtered to the walls\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.renderTakeoff({ sheetName: \"Takeoff\" })\n * ```\n */\n public abstract renderTakeoff(\n options?: { sheetName?: string; title?: string; filter?: string },\n ): PluginApiReturn<PluginProgramSpreadsheetRenderResult>\n\n /**\n * Render the area program onto a sheet.\n *\n * A specialization of the render* family: the **host pulls and projects the\n * current program dataset itself** (departments with area targets vs allocated)\n * — the plugin supplies only the target `sheetName`, an optional `title`, and an\n * optional `filter`; there is **no data argument**. Returns the same\n * rendered-artifact record as {@linkcode PluginProgramSpreadsheetApi.render}.\n * _(Authored ahead — optional via the `spreadsheet?` mount until the host\n * round-trip is live.)_\n *\n * @param options - Optional `sheetName`, `title`, and `filter` (a\n * {@linkcode PluginProgramSpreadsheetRenderDatasetArgs}).\n * @returns A {@linkcode PluginProgramSpreadsheetRenderResult} with the written\n * ranges and counts.\n * @throws If the program cannot be rendered.\n *\n * @examplePrompt Render the area program onto a sheet\n * @examplePrompt Put the department program on a spreadsheet\n * @examplePrompt Generate the program schedule sheet titled Program\n * @examplePrompt Render the program filtered to the residential departments\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.renderProgram({ sheetName: \"Program\" })\n * ```\n */\n public abstract renderProgram(\n options?: { sheetName?: string; title?: string; filter?: string },\n ): PluginApiReturn<PluginProgramSpreadsheetRenderResult>\n\n /**\n * Export the whole report workbook to a file (xlsx, pdf, or csv).\n *\n * Returns the file content as base64 so the plugin can download, upload, or\n * attach it. This is the workbook **file** export; to read cell **values** back\n * as data, use {@linkcode PluginProgramSpreadsheetApi.getSheetData} instead.\n *\n * @param format - The file format to export the workbook to.\n * @param options - Optional `fileName` (without extension); a default is used\n * when omitted.\n * @returns A {@linkcode PluginProgramSpreadsheetExportResult} with the file's\n * `fileName`, `mimeType`, and base64 `dataBase64`.\n * @throws If the workbook cannot be serialized to the requested format.\n *\n * @examplePrompt Export the report as an Excel file\n * @examplePrompt Download the whole workbook as a PDF\n * @examplePrompt Export the program workbook to xlsx\n * @examplePrompt Save the report as a csv file\n *\n * # Example\n * ```ts\n * const file = await snaptrude.program.spreadsheet.export(\"xlsx\")\n * // file.fileName, file.mimeType, file.dataBase64\n * ```\n */\n public abstract export(\n format: PluginSpreadsheetExportFormat,\n options?: { fileName?: string },\n ): PluginApiReturn<PluginProgramSpreadsheetExportResult>\n\n /**\n * List the sheets in the report workbook.\n *\n * @returns A {@linkcode PluginProgramSpreadsheetListSheetsResult} with each sheet's\n * name/index/visibility/size, plus the active sheet name.\n *\n * @examplePrompt List the sheets in the spreadsheet\n * @examplePrompt What sheets are in the report workbook?\n * @examplePrompt Which sheet is currently active?\n * @examplePrompt How many sheets does the report have?\n *\n * # Example\n * ```ts\n * const { sheets, activeSheet } = await snaptrude.program.spreadsheet.listSheets()\n * ```\n */\n public abstract listSheets(): PluginApiReturn<PluginProgramSpreadsheetListSheetsResult>\n\n /**\n * Read a sheet's data back as a matrix (and optionally as header-keyed records).\n *\n * @param sheetName - Sheet to read.\n * @param options - Optional `range` (A1; omit to read the sheet's used range)\n * and `header` (`true` to also get records keyed by the header row).\n * @returns A {@linkcode PluginProgramSpreadsheetGetSheetDataResult} with the read\n * `range`, `values` matrix, and optional `records`.\n * @throws If the sheet does not exist or the range is invalid.\n *\n * @examplePrompt Read the data back from the Program sheet\n * @examplePrompt Get the values in range A1:D20 of a sheet\n * @examplePrompt Read a sheet as rows of records keyed by header\n * @examplePrompt What's in the takeoff sheet right now?\n *\n * # Example\n * ```ts\n * const { values, records } = await snaptrude.program.spreadsheet.getSheetData(\n * \"Program\",\n * { header: true },\n * )\n * ```\n */\n public abstract getSheetData(\n sheetName: string,\n options?: { range?: string; header?: boolean },\n ): PluginApiReturn<PluginProgramSpreadsheetGetSheetDataResult>\n\n /**\n * Add a chart to a sheet, driven by a cell range.\n *\n * @param sheetName - Sheet to add the chart to.\n * @param chartType - Chart type (see {@linkcode PluginSpreadsheetChartType}).\n * @param dataRange - A1 range driving the chart.\n * @param options - Optional `title`, `position` (sheet coords), and `size` (px).\n * @returns A {@linkcode PluginProgramSpreadsheetAddChartResult} with the new\n * chart's id.\n * @throws If the sheet or data range is invalid.\n *\n * @examplePrompt Add a bar chart of the department areas\n * @examplePrompt Insert a pie chart from range B2:C10\n * @examplePrompt Put a column chart on the Program sheet\n * @examplePrompt Chart the area breakdown by department\n *\n * # Example\n * ```ts\n * const { chartId } = await snaptrude.program.spreadsheet.addChart(\n * \"Program\",\n * \"column\",\n * \"A1:B10\",\n * { title: \"Area by department\" },\n * )\n * ```\n */\n public abstract addChart(\n sheetName: string,\n chartType: PluginSpreadsheetChartType,\n dataRange: string,\n options?: {\n title?: string\n position?: { x: number; y: number }\n size?: { width: number; height: number }\n },\n ): PluginApiReturn<PluginProgramSpreadsheetAddChartResult>\n\n /**\n * Highlight a range of cells (background color and optional emphasis).\n *\n * @param sheetName - Sheet containing the range.\n * @param range - A1 range to highlight.\n * @param options - Optional `color` (CSS hex; a default emphasis is used when\n * omitted) and `bold`.\n * @returns A {@linkcode PluginProgramSpreadsheetHighlightCellsResult} echoing the\n * highlighted sheet and range.\n * @throws If the sheet or range is invalid.\n *\n * @examplePrompt Highlight the cells that are over budget\n * @examplePrompt Color range A2:A10 red\n * @examplePrompt Highlight B2:D2 in yellow\n * @examplePrompt Emphasize the totals row on the Program sheet\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.highlightCells(\"Program\", \"A2:A10\", {\n * color: \"#ffe08a\",\n * })\n * ```\n */\n public abstract highlightCells(\n sheetName: string,\n range: string,\n options?: { color?: string; bold?: boolean },\n ): PluginApiReturn<PluginProgramSpreadsheetHighlightCellsResult>\n\n // --- Program / takeoff dataset reads (the data the render* methods draw) ---\n\n /**\n * Read the area-program dataset (departments with target vs allocated area).\n *\n * Returns the same figures {@linkcode PluginProgramSpreadsheetApi.renderProgram}\n * projects onto a sheet, as render-ready rows — so a plugin can inspect or\n * transform the program before rendering it (or render it itself via\n * {@linkcode PluginProgramSpreadsheetApi.render}). For the canonical\n * area-program summary read, see {@linkcode PluginProgramMetricsApi.get}.\n *\n * @returns A {@linkcode PluginProgramSpreadsheetGetProgramResult} with per-department\n * rows (`targetArea`/`allocatedArea`/`variance`), totals, and the report `units`.\n *\n * @examplePrompt Get the area program data\n * @examplePrompt Read the department program before I render it\n * @examplePrompt Give me the program rows with target vs allocated area\n * @examplePrompt What's the program dataset the report is built from?\n *\n * # Example\n * ```ts\n * const program = await snaptrude.program.spreadsheet.getProgram()\n * for (const row of program.rows) console.log(row.name, row.allocatedArea, row.targetArea)\n * ```\n */\n public abstract getProgram(): PluginApiReturn<PluginProgramSpreadsheetGetProgramResult>\n\n /**\n * Read the quantity/material takeoff dataset (per-element quantities).\n *\n * Returns the same rows {@linkcode PluginProgramSpreadsheetApi.renderTakeoff}\n * projects onto a sheet — one record per counted element (category, item,\n * level, quantity, unit) — so a plugin can inspect or transform the takeoff\n * before rendering it (or render it itself via\n * {@linkcode PluginProgramSpreadsheetApi.render}).\n *\n * @returns A {@linkcode PluginProgramSpreadsheetGetTakeoffResult} with the takeoff\n * `rows`, a `rowCount`, and the `generatedAt` timestamp.\n *\n * @examplePrompt Get the takeoff data\n * @examplePrompt Read the quantity takeoff rows\n * @examplePrompt Give me the per-element quantities before I render them\n * @examplePrompt What's in the material takeoff right now?\n *\n * # Example\n * ```ts\n * const takeoff = await snaptrude.program.spreadsheet.getTakeoff()\n * console.log(takeoff.rowCount, \"elements\")\n * ```\n */\n public abstract getTakeoff(): PluginApiReturn<PluginProgramSpreadsheetGetTakeoffResult>\n\n // --- Sheet construction (lower-level cell writes; render is the high-level path) ---\n\n /**\n * Create (or reuse/replace) a named sheet in the report workbook.\n *\n * The blank-canvas complement to {@linkcode PluginProgramSpreadsheetApi.render}:\n * use it when you want an empty sheet to write into with\n * {@linkcode PluginProgramSpreadsheetApi.setValues} /\n * {@linkcode PluginProgramSpreadsheetApi.setFormulas}. By default an existing\n * sheet of the same name is reused; pass `whenExists` to replace or error.\n *\n * @param name - The sheet name to create.\n * @param whenExists - Behaviour if the name exists: `\"reuse\"` (default),\n * `\"replace\"`, or `\"error\"`.\n * @returns A {@linkcode PluginProgramSpreadsheetCreateSheetResult} with the resolved\n * `sheetName`, whether it `replaced` an existing sheet, and its `sheetIndex`.\n * @throws If the sheet exists and `whenExists` is `\"error\"`.\n *\n * @examplePrompt Create a sheet called Summary\n * @examplePrompt Add a new blank sheet named Takeoff\n * @examplePrompt Make a sheet, replacing it if it already exists\n * @examplePrompt Start a fresh sheet to write into\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.createSheet(\"Summary\")\n * ```\n */\n public abstract createSheet(\n name: string,\n whenExists?: PluginSpreadsheetWhenExists,\n ): PluginApiReturn<PluginProgramSpreadsheetCreateSheetResult>\n\n /**\n * Write a block of raw values into a sheet, anchored at a cell.\n *\n * The low-level cell-write path (the high-level path is\n * {@linkcode PluginProgramSpreadsheetApi.render}, which adds a header, format,\n * and totals). Values are written row-major from `startCell` (default `\"A1\"`);\n * columns are auto-sized to fit.\n *\n * @param sheetName - Sheet to write into.\n * @param values - Row-major matrix of values to write.\n * @param startCell - Top-left anchor in A1 notation (default `\"A1\"`).\n * @returns A {@linkcode PluginProgramSpreadsheetSetValuesResult} with the written\n * `startCell`, `rowCount`, and `colCount`.\n * @throws If the sheet does not exist or `startCell` is invalid.\n *\n * @examplePrompt Write these rows to the sheet starting at A1\n * @examplePrompt Put this data into the Summary sheet\n * @examplePrompt Set the values in the takeoff sheet from B2\n * @examplePrompt Drop this matrix of numbers onto a sheet\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.setValues(\n * \"Summary\",\n * [[\"Department\", \"Area\"], [\"FOH\", 120.5]],\n * \"A1\",\n * )\n * ```\n */\n public abstract setValues(\n sheetName: string,\n values: PluginSpreadsheetCell[][],\n startCell?: string,\n ): PluginApiReturn<PluginProgramSpreadsheetSetValuesResult>\n\n /**\n * Set formulas on individual cells of a sheet.\n *\n * Each entry targets one cell (A1 notation) with a formula expression (a\n * leading `=` is optional). Pairs with\n * {@linkcode PluginProgramSpreadsheetApi.recalculate} when you need to force a\n * recompute.\n *\n * @param sheetName - Sheet to set formulas on.\n * @param formulas - The cell → formula assignments (see\n * {@linkcode PluginSpreadsheetFormula}).\n * @returns A {@linkcode PluginProgramSpreadsheetSetFormulasResult} with the `count`\n * of formulas set.\n * @throws If the sheet does not exist or a cell address is invalid.\n *\n * @examplePrompt Put a SUM formula in cell B10\n * @examplePrompt Set formulas totalling each column\n * @examplePrompt Add a formula to compute the variance column\n * @examplePrompt Write =SUM(B2:B9) into B10 on the Summary sheet\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.setFormulas(\"Summary\", [\n * { cell: \"B10\", formula: \"=SUM(B2:B9)\" },\n * ])\n * ```\n */\n public abstract setFormulas(\n sheetName: string,\n formulas: PluginSpreadsheetFormula[],\n ): PluginApiReturn<PluginProgramSpreadsheetSetFormulasResult>\n\n // --- Formatting ---\n\n /**\n * Apply cell styles to one or more ranges of a sheet.\n *\n * Sets fill/text color, font, alignment, and number format on each given range.\n * For a quick single-range emphasis,\n * {@linkcode PluginProgramSpreadsheetApi.highlightCells} is the shortcut.\n *\n * @param sheetName - Sheet containing the ranges.\n * @param ranges - Range → style assignments (each a range + a\n * {@linkcode PluginSpreadsheetCellStyle}).\n * @returns A {@linkcode PluginProgramSpreadsheetSetStylesResult} with the `count` of\n * ranges styled.\n * @throws If the sheet does not exist or a range is invalid.\n *\n * @examplePrompt Make the header row bold with a grey fill\n * @examplePrompt Right-align the numbers in column B\n * @examplePrompt Format A1:D1 with a background color and bold text\n * @examplePrompt Style the totals row\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.setStyles(\"Summary\", [\n * { range: \"A1:D1\", style: { fontWeight: \"bold\", backColor: \"#eef\" } },\n * ])\n * ```\n */\n public abstract setStyles(\n sheetName: string,\n ranges: PluginSpreadsheetRangeStyle[],\n ): PluginApiReturn<PluginProgramSpreadsheetSetStylesResult>\n\n /**\n * Merge a contiguous range of cells into a single spanned cell.\n *\n * Optionally sets the merged cell's value. (Verb ruling: `merge` is a\n * spreadsheet-domain verb here — spanning cells — not the CSG-solid `union`.)\n *\n * @param sheetName - Sheet containing the range.\n * @param range - A1 range to merge into one spanned cell.\n * @param value - Optional value to set in the merged (top-left) cell.\n * @returns A {@linkcode PluginProgramSpreadsheetMergeCellsResult} echoing the merged\n * sheet and range.\n * @throws If the sheet does not exist or the range is invalid.\n *\n * @examplePrompt Merge cells A1 to D1 for the title\n * @examplePrompt Span the header across the first four columns\n * @examplePrompt Merge A1:D1 and set it to \"Program Summary\"\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.mergeCells(\"Summary\", \"A1:D1\", \"Program Summary\")\n * ```\n */\n public abstract mergeCells(\n sheetName: string,\n range: string,\n value?: PluginSpreadsheetCell,\n ): PluginApiReturn<PluginProgramSpreadsheetMergeCellsResult>\n\n /**\n * Add a conditional-formatting rule to a range.\n *\n * Currently supports data-bar rules (a proportional in-cell bar); more rule\n * types are reserved. For static (non-conditional) emphasis use\n * {@linkcode PluginProgramSpreadsheetApi.highlightCells} or\n * {@linkcode PluginProgramSpreadsheetApi.setStyles}.\n *\n * @param sheetName - Sheet containing the range.\n * @param range - A1 range to format.\n * @param rule - The conditional-format rule (see\n * {@linkcode PluginSpreadsheetConditionalRule}).\n * @returns A {@linkcode PluginProgramSpreadsheetAddConditionalFormattingResult} with\n * whether a rule was `created`.\n * @throws If the sheet does not exist or the range is invalid.\n *\n * @examplePrompt Add data bars to the area column\n * @examplePrompt Show a proportional bar inside cells B2:B10\n * @examplePrompt Add conditional formatting data bars to the quantities\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.addConditionalFormatting(\"Summary\", \"B2:B10\", {\n * type: \"dataBar\",\n * color: \"#4f9cf9\",\n * })\n * ```\n */\n public abstract addConditionalFormatting(\n sheetName: string,\n range: string,\n rule: PluginSpreadsheetConditionalRule,\n ): PluginApiReturn<PluginProgramSpreadsheetAddConditionalFormattingResult>\n\n // --- Recalculation & atomic batching ---\n\n /**\n * Recompute the workbook's formula results.\n *\n * Recalculates every formula (or, when `sheetName` is given, focuses that sheet\n * before recalculating the workbook). (Verb ruling: `recalculate` recomputes\n * formulas — distinct from {@linkcode PluginProgramSpreadsheetBindingsApi.refresh},\n * which re-pulls a binding's source data.)\n *\n * @param options - Optional `sheetName` to focus before recalculating; omit for\n * the whole workbook.\n * @returns A {@linkcode PluginProgramSpreadsheetRecalculateResult} with the recompute\n * `scope` and the focused `sheetName` (or `null`).\n *\n * @examplePrompt Recalculate the workbook\n * @examplePrompt Recompute all the formulas\n * @examplePrompt Recalculate the Summary sheet\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.recalculate()\n * ```\n */\n public abstract recalculate(\n options?: { sheetName?: string },\n ): PluginApiReturn<PluginProgramSpreadsheetRecalculateResult>\n\n /**\n * Run a sequence of sheet operations as one atomic, undoable transaction.\n *\n * Batches cell-construction operations (createSheet/setValues/setFormulas/\n * setStyles/mergeCells) so they commit together and undo as a single step, with\n * events suspended for speed. (`transaction` is the sanctioned §4 atomic-batch\n * verb.)\n *\n * @param operations - The operations to run in order. Each operation's `args`\n * stays that method's schema **object** (the wire shape), not positional.\n * @param label - Optional undo-history label for the batch.\n * @returns A {@linkcode PluginProgramSpreadsheetTransactionResult} with the\n * `operationCount` and each operation's `results`.\n * @throws If any operation names an unsupported method or fails.\n *\n * @examplePrompt Create a sheet and write to it in one atomic step\n * @examplePrompt Batch these sheet edits as a single undoable action\n * @examplePrompt Run these operations together as one transaction\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.transaction(\n * [\n * { method: \"createSheet\", args: { name: \"Summary\" } },\n * { method: \"setValues\", args: { sheetName: \"Summary\", values: [[\"A\", 1]] } },\n * ],\n * \"Build summary\",\n * )\n * ```\n */\n public abstract transaction(\n operations: PluginSpreadsheetTransactionOp[],\n label?: string,\n ): PluginApiReturn<PluginProgramSpreadsheetTransactionResult>\n\n // --- Meta: script escape hatch, audit log, liveness ---\n\n /**\n * Run an author-supplied script against a sandboxed workbook facade.\n *\n * The escape hatch for advanced automation the typed methods don't cover: the\n * `script` runs against a restricted `workbook` object with browser/network\n * globals blocked, and its return value is handed back as `result`. Prefer the\n * typed methods where they exist. (Verb ruling: `run` executes a script.)\n *\n * @param script - Script source, run against the sandboxed `workbook` facade.\n * @returns A {@linkcode PluginProgramSpreadsheetRunScriptResult} with the script's\n * `result`.\n * @throws If the script uses a blocked browser/network API or throws at runtime.\n *\n * @examplePrompt Run this SpreadJS script against the workbook\n * @examplePrompt Execute a custom script on the sheets\n * @examplePrompt Run a script to tweak the workbook\n *\n * # Example\n * ```ts\n * const { result } = await snaptrude.program.spreadsheet.runScript(\n * \"return workbook.getSheetCount();\",\n * )\n * ```\n */\n public abstract runScript(\n script: string,\n ): PluginApiReturn<PluginProgramSpreadsheetRunScriptResult>\n\n /**\n * Read the recent audit log of program-spreadsheet operations.\n *\n * Returns the most recent operations performed through this API (method, sheet,\n * status, summary, timestamp), newest first — useful for showing the user what\n * a plugin changed. (Renamed from the host's `getRecentEntries` for §4 `get`\n * compliance.)\n *\n * @param options - Optional `limit` on the entries returned (clamped 1–100,\n * default 20).\n * @returns A {@linkcode PluginProgramSpreadsheetGetAuditLogResult} with the audit\n * `entries`, newest first.\n *\n * @examplePrompt Show the recent spreadsheet actions\n * @examplePrompt What did the plugin change in the workbook?\n * @examplePrompt Get the last 10 audit log entries\n * @examplePrompt Read the program spreadsheet audit log\n *\n * # Example\n * ```ts\n * const { entries } = await snaptrude.program.spreadsheet.getAuditLog({ limit: 10 })\n * ```\n */\n public abstract getAuditLog(\n options?: { limit?: number },\n ): PluginApiReturn<PluginProgramSpreadsheetGetAuditLogResult>\n\n /**\n * Ping the program-mode spreadsheet bridge to check it is reachable.\n *\n * A liveness probe: resolves with `{ pong: true }` when the program-mode\n * workbook bridge is up. (Verb ruling: `ping` is a meta liveness verb.)\n *\n * @returns A {@linkcode PluginProgramSpreadsheetPingResult} — `{ pong: true }` when\n * the bridge is reachable.\n *\n * @examplePrompt Ping the spreadsheet bridge\n * @examplePrompt Is the program spreadsheet available?\n * @examplePrompt Check the spreadsheet connection is alive\n *\n * # Example\n * ```ts\n * const { pong } = await snaptrude.program.spreadsheet.ping()\n * ```\n */\n public abstract ping(): PluginApiReturn<PluginProgramSpreadsheetPingResult>\n}\n\n/**\n * Program-spreadsheet templates — capture a sheet's layout as a named, reusable\n * template and re-apply it to another sheet.\n *\n * Accessed via `snaptrude.program.spreadsheet.templates`.\n */\nexport abstract class PluginProgramSpreadsheetTemplatesApi {\n constructor() {}\n\n /**\n * Save a sheet's current layout as a named template.\n *\n * (Renamed from the host's `save` to `create` for §4 compliance.)\n *\n * @param name - Template name (re-saving the same name overwrites it).\n * @param sheetName - The source sheet to capture.\n * @param scope - Template scope: `\"project\"` (default) or `\"global\"`.\n * @returns A {@linkcode PluginProgramSpreadsheetTemplatesCreateResult} with the new\n * template's `id`, `name`, `scope`, and source `sheetName`.\n * @throws If the source sheet does not exist.\n *\n * @examplePrompt Save this sheet as a reusable template\n * @examplePrompt Create a template from the Summary sheet\n * @examplePrompt Save the current layout as a template called \"Cover\"\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.templates.create(\"Cover\", \"Summary\")\n * ```\n */\n public abstract create(\n name: string,\n sheetName: string,\n scope?: PluginSpreadsheetTemplateScope,\n ): PluginApiReturn<PluginProgramSpreadsheetTemplatesCreateResult>\n\n /**\n * Apply a saved template to a target sheet (create-or-replace).\n *\n * @param name - The template to apply.\n * @param targetSheetName - The sheet to create/replace from the template.\n * @returns A {@linkcode PluginProgramSpreadsheetTemplatesApplyResult} echoing the\n * applied template and target sheet.\n * @throws If the named template does not exist.\n *\n * @examplePrompt Apply the Cover template to a new sheet\n * @examplePrompt Use my saved template on the Report sheet\n * @examplePrompt Apply template \"Cover\" to sheet \"Report\"\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.templates.apply(\"Cover\", \"Report\")\n * ```\n */\n public abstract apply(\n name: string,\n targetSheetName: string,\n ): PluginApiReturn<PluginProgramSpreadsheetTemplatesApplyResult>\n}\n\n/**\n * Program-spreadsheet data bindings — bind a live program dataset to a sheet\n * range so it can be refreshed on demand.\n *\n * A binding links a dataset (e.g. the takeoff) to a target sheet range; a refresh\n * re-pulls the current data and rewrites the range. Accessed via\n * `snaptrude.program.spreadsheet.bindings`.\n */\nexport abstract class PluginProgramSpreadsheetBindingsApi {\n constructor() {}\n\n /**\n * Create a named binding from a dataset to a sheet range (and do an initial refresh).\n *\n * @param name - Binding name (re-using a name overwrites it).\n * @param source - The dataset to bind (see\n * {@linkcode PluginSpreadsheetBindingSource}).\n * @param target - The target sheet range (see\n * {@linkcode PluginSpreadsheetBindingTarget}).\n * @param mode - How a refresh writes into the target (default `\"replaceRange\"`).\n * @returns A {@linkcode PluginProgramSpreadsheetBindingsCreateResult} — the stored\n * binding plus the `refresh` result of the initial pull.\n * @throws If the target sheet does not exist.\n *\n * @examplePrompt Bind the takeoff to the Data sheet\n * @examplePrompt Create a live binding from the takeoff to A1 on Data\n * @examplePrompt Link the takeoff dataset to a sheet range\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.bindings.create(\n * \"takeoff\",\n * { dataset: \"takeoff\" },\n * { sheetName: \"Data\", startCell: \"A1\" },\n * )\n * ```\n */\n public abstract create(\n name: string,\n source: PluginSpreadsheetBindingSource,\n target: PluginSpreadsheetBindingTarget,\n mode?: PluginSpreadsheetBindingMode,\n ): PluginApiReturn<PluginProgramSpreadsheetBindingsCreateResult>\n\n /**\n * Refresh one binding (by name) or all bindings, re-pulling their source data.\n *\n * (Verb ruling: `refresh` re-pulls a binding's live source into its target\n * range — distinct from {@linkcode PluginProgramSpreadsheetApi.recalculate},\n * which recomputes formulas.)\n *\n * @param options - Optional binding `name`; omit it to refresh every binding.\n * @returns A {@linkcode PluginProgramSpreadsheetBindingsRefreshResult} with a\n * `refreshed` entry per binding that was updated.\n * @throws If a `name` is given but no binding with that name exists.\n *\n * @examplePrompt Refresh the takeoff binding\n * @examplePrompt Re-pull all my data bindings\n * @examplePrompt Refresh every binding on the sheets\n *\n * # Example\n * ```ts\n * await snaptrude.program.spreadsheet.bindings.refresh({ name: \"takeoff\" })\n * ```\n */\n public abstract refresh(\n options?: { name?: string },\n ): PluginApiReturn<PluginProgramSpreadsheetBindingsRefreshResult>\n\n /**\n * List all data bindings in the workbook.\n *\n * @returns A {@linkcode PluginProgramSpreadsheetBindingsListResult} with every\n * stored {@linkcode PluginSpreadsheetBinding}.\n *\n * @examplePrompt List the data bindings\n * @examplePrompt What bindings are set up on the sheets?\n * @examplePrompt Show all the live data bindings\n *\n * # Example\n * ```ts\n * const { bindings } = await snaptrude.program.spreadsheet.bindings.list()\n * ```\n */\n public abstract list(): PluginApiReturn<PluginProgramSpreadsheetBindingsListResult>\n}\n\n/** A single spreadsheet cell value. */\nexport const PluginSpreadsheetCell = z.union([\n z.string(),\n z.number(),\n z.boolean(),\n z.null(),\n])\nexport type PluginSpreadsheetCell = z.infer<typeof PluginSpreadsheetCell>\n\n/** Horizontal alignment for a rendered column. */\nexport const PluginSpreadsheetAlign = z.enum([\"left\", \"center\", \"right\"])\nexport type PluginSpreadsheetAlign = z.infer<typeof PluginSpreadsheetAlign>\n\n/**\n * A column definition for {@linkcode PluginProgramSpreadsheetApi.render}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `key` | `string` | Key into each row object |\n * | `header` | `string` | Column header text |\n * | `width` | `number?` | Fixed column width in px; auto-fit when omitted |\n * | `format` | `string?` | Number/date format string applied to the data cells |\n * | `align` | `\"left\" \\| \"center\" \\| \"right\"?` | Cell alignment |\n */\nexport const PluginSpreadsheetColumn = z.object({\n key: z.string(),\n header: z.string(),\n width: z.number().optional(),\n format: z.string().optional(),\n align: PluginSpreadsheetAlign.optional(),\n})\nexport type PluginSpreadsheetColumn = z.infer<typeof PluginSpreadsheetColumn>\n\n/**\n * A totals-row aggregation for {@linkcode PluginProgramSpreadsheetApi.render}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `column` | `string` | The {@linkcode PluginSpreadsheetColumn} `key` to aggregate |\n * | `fn` | `\"sum\" \\| \"avg\" \\| \"count\" \\| \"min\" \\| \"max\"` | Aggregation function |\n * | `label` | `string?` | Optional label printed in the first column of the totals row |\n */\nexport const PluginSpreadsheetTotal = z.object({\n column: z.string(),\n fn: z.enum([\"sum\", \"avg\", \"count\", \"min\", \"max\"]),\n label: z.string().optional(),\n})\nexport type PluginSpreadsheetTotal = z.infer<typeof PluginSpreadsheetTotal>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.render}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | Target sheet name |\n * | `columns` | {@linkcode PluginSpreadsheetColumn}`[]` | Column definitions (at least one) |\n * | `rows` | `Record<string, cell>[]` | Row objects keyed by column `key` |\n * | `title` | `string?` | Optional title rendered above the header |\n * | `startCell` | `string?` | Top-left anchor in A1 notation (default `\"A1\"`) |\n * | `whenExists` | `\"replace\" \\| \"error\"?` | Behaviour if the sheet exists (default `\"replace\"`) |\n * | `asTable` | `boolean?` | Wrap the block in a table (default `true`) |\n * | `freezeHeader` | `boolean?` | Freeze rows above the data (default `true`) |\n * | `totals` | {@linkcode PluginSpreadsheetTotal}`[]?` | Optional totals row |\n */\nexport const PluginProgramSpreadsheetRenderArgs = z.object({\n sheetName: z.string(),\n columns: z.array(PluginSpreadsheetColumn),\n rows: z.array(z.record(z.string(), PluginSpreadsheetCell)),\n title: z.string().optional(),\n startCell: z.string().optional(),\n whenExists: z.enum([\"replace\", \"error\"]).optional(),\n asTable: z.boolean().optional(),\n freezeHeader: z.boolean().optional(),\n totals: z.array(PluginSpreadsheetTotal).optional(),\n})\nexport type PluginProgramSpreadsheetRenderArgs = z.infer<\n typeof PluginProgramSpreadsheetRenderArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.render}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | The sheet that was written |\n * | `range` | `string` | A1 range covering the full written block (title + header + data + totals) |\n * | `headerRange` | `string` | A1 range of the header row alone |\n * | `rowCount` | `number` | Number of data rows written (excludes title/header/totals) |\n * | `colCount` | `number` | Number of columns written |\n * | `tableName` | `string \\| null` | The created table's name, or `null` when not wrapped as a table |\n * | `replaced` | `boolean` | Whether an existing sheet was replaced |\n */\nexport const PluginProgramSpreadsheetRenderResult = z.object({\n sheetName: z.string(),\n range: z.string(),\n headerRange: z.string(),\n rowCount: z.number(),\n colCount: z.number(),\n tableName: z.string().nullable(),\n replaced: z.boolean(),\n})\nexport type PluginProgramSpreadsheetRenderResult = z.infer<\n typeof PluginProgramSpreadsheetRenderResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.renderTakeoff} and\n * {@linkcode PluginProgramSpreadsheetApi.renderProgram} — the dataset render\n * methods. There is **no data argument**: the host pulls and projects the\n * takeoff/program dataset itself. All fields are optional. (Both methods share\n * this args type, as `import.image`/`import.pdf` share their args.)\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string?` | Target sheet name (a default is used when omitted) |\n * | `title` | `string?` | Optional title rendered above the table |\n * | `filter` | `string?` | Optional dataset-filter expression to narrow the rows |\n */\nexport const PluginProgramSpreadsheetRenderDatasetArgs = z.object({\n sheetName: z.string().optional(),\n title: z.string().optional(),\n filter: z.string().optional(),\n})\nexport type PluginProgramSpreadsheetRenderDatasetArgs = z.infer<\n typeof PluginProgramSpreadsheetRenderDatasetArgs\n>\n\n/** The workbook export file format. */\nexport const PluginSpreadsheetExportFormat = z.enum([\"xlsx\", \"pdf\", \"csv\"])\nexport type PluginSpreadsheetExportFormat = z.infer<\n typeof PluginSpreadsheetExportFormat\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.export}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `format` | `\"xlsx\" \\| \"pdf\" \\| \"csv\"` | The file format to export the workbook to |\n * | `fileName` | `string?` | Desired file name (without extension); a default is used when omitted |\n */\nexport const PluginProgramSpreadsheetExportArgs = z.object({\n format: PluginSpreadsheetExportFormat,\n fileName: z.string().optional(),\n})\nexport type PluginProgramSpreadsheetExportArgs = z.infer<\n typeof PluginProgramSpreadsheetExportArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.export} — the exported workbook file.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `format` | `\"xlsx\" \\| \"pdf\" \\| \"csv\"` | The format the file was exported in |\n * | `fileName` | `string` | The file name (with extension) |\n * | `mimeType` | `string` | The file's MIME type |\n * | `dataBase64` | `string` | The file's bytes, base64-encoded |\n */\nexport const PluginProgramSpreadsheetExportResult = z.object({\n format: PluginSpreadsheetExportFormat,\n fileName: z.string(),\n mimeType: z.string(),\n dataBase64: z.string(),\n})\nexport type PluginProgramSpreadsheetExportResult = z.infer<\n typeof PluginProgramSpreadsheetExportResult\n>\n\n/**\n * Metadata for one sheet in {@linkcode PluginProgramSpreadsheetListSheetsResult}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string` | Sheet name |\n * | `index` | `number` | Zero-based sheet index |\n * | `visible` | `boolean` | Whether the sheet is visible |\n * | `rowCount` | `number` | Total rows in the sheet |\n * | `colCount` | `number` | Total columns in the sheet |\n */\nexport const PluginSpreadsheetSheetInfo = z.object({\n name: z.string(),\n index: z.number(),\n visible: z.boolean(),\n rowCount: z.number(),\n colCount: z.number(),\n})\nexport type PluginSpreadsheetSheetInfo = z.infer<\n typeof PluginSpreadsheetSheetInfo\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.listSheets}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheets` | {@linkcode PluginSpreadsheetSheetInfo}`[]` | All sheets in the workbook |\n * | `activeSheet` | `string \\| null` | The active sheet name, or `null` |\n */\nexport const PluginProgramSpreadsheetListSheetsResult = z.object({\n sheets: z.array(PluginSpreadsheetSheetInfo),\n activeSheet: z.string().nullable(),\n})\nexport type PluginProgramSpreadsheetListSheetsResult = z.infer<\n typeof PluginProgramSpreadsheetListSheetsResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.getSheetData}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | Sheet to read |\n * | `range` | `string?` | A1 range; defaults to the sheet's used range |\n * | `header` | `boolean?` | When `true`, also return records keyed by the first (header) row |\n */\nexport const PluginProgramSpreadsheetGetSheetDataArgs = z.object({\n sheetName: z.string(),\n range: z.string().optional(),\n header: z.boolean().optional(),\n})\nexport type PluginProgramSpreadsheetGetSheetDataArgs = z.infer<\n typeof PluginProgramSpreadsheetGetSheetDataArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.getSheetData}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | The sheet that was read |\n * | `range` | `string` | A1 range that was read |\n * | `values` | `cell[][]` | Row-major matrix of cell values |\n * | `records` | `Record<string, cell>[]?` | Present only when `header` was `true`: rows keyed by header |\n */\nexport const PluginProgramSpreadsheetGetSheetDataResult = z.object({\n sheetName: z.string(),\n range: z.string(),\n values: z.array(z.array(PluginSpreadsheetCell)),\n records: z.array(z.record(z.string(), PluginSpreadsheetCell)).optional(),\n})\nexport type PluginProgramSpreadsheetGetSheetDataResult = z.infer<\n typeof PluginProgramSpreadsheetGetSheetDataResult\n>\n\n/** Chart type for {@linkcode PluginProgramSpreadsheetApi.addChart}. */\nexport const PluginSpreadsheetChartType = z.enum([\n \"column\",\n \"bar\",\n \"line\",\n \"pie\",\n \"area\",\n \"scatter\",\n])\nexport type PluginSpreadsheetChartType = z.infer<\n typeof PluginSpreadsheetChartType\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.addChart}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | Sheet to add the chart to |\n * | `chartType` | `\"column\" \\| \"bar\" \\| \"line\" \\| \"pie\" \\| \"area\" \\| \"scatter\"` | Chart type |\n * | `dataRange` | `string` | A1 range driving the chart |\n * | `title` | `string?` | Optional chart title |\n * | `position` | `{ x; y }?` | Top-left position (sheet coords) |\n * | `size` | `{ width; height }?` | Chart size in px |\n */\nexport const PluginProgramSpreadsheetAddChartArgs = z.object({\n sheetName: z.string(),\n chartType: PluginSpreadsheetChartType,\n dataRange: z.string(),\n title: z.string().optional(),\n position: z.object({ x: z.number(), y: z.number() }).optional(),\n size: z.object({ width: z.number(), height: z.number() }).optional(),\n})\nexport type PluginProgramSpreadsheetAddChartArgs = z.infer<\n typeof PluginProgramSpreadsheetAddChartArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.addChart}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `chartId` | `string` | Id of the created chart |\n */\nexport const PluginProgramSpreadsheetAddChartResult = z.object({\n chartId: z.string(),\n})\nexport type PluginProgramSpreadsheetAddChartResult = z.infer<\n typeof PluginProgramSpreadsheetAddChartResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.highlightCells}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | Sheet containing the range |\n * | `range` | `string` | A1 range to highlight |\n * | `color` | `string?` | CSS hex background color (a default emphasis is used when omitted) |\n * | `bold` | `boolean?` | Also bold the text |\n */\nexport const PluginProgramSpreadsheetHighlightCellsArgs = z.object({\n sheetName: z.string(),\n range: z.string(),\n color: z.string().optional(),\n bold: z.boolean().optional(),\n})\nexport type PluginProgramSpreadsheetHighlightCellsArgs = z.infer<\n typeof PluginProgramSpreadsheetHighlightCellsArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.highlightCells}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | The sheet that was highlighted |\n * | `range` | `string` | The range that was highlighted |\n */\nexport const PluginProgramSpreadsheetHighlightCellsResult = z.object({\n sheetName: z.string(),\n range: z.string(),\n})\nexport type PluginProgramSpreadsheetHighlightCellsResult = z.infer<\n typeof PluginProgramSpreadsheetHighlightCellsResult\n>\n\n// --- getProgram / getTakeoff dataset reads ---------------------------------\n\n/**\n * One department row in the area-program dataset. Areas are in the enclosing\n * {@linkcode PluginProgramSpreadsheetGetProgramResult}'s `units`. This mirrors\n * {@linkcode PluginProgramDepartmentMetric}, plus a derived `variance`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `departmentId` | `string` | Department id |\n * | `name` | `string` | Department name |\n * | `targetArea` | `number \\| null` | Target area, or `null` if no target is set |\n * | `allocatedArea` | `number` | Area currently allocated to this department |\n * | `variance` | `number \\| null` | `allocatedArea − targetArea`, or `null` when no target |\n */\nexport const PluginSpreadsheetProgramRow = z.object({\n departmentId: z.string(),\n name: z.string(),\n targetArea: z.number().nullable(),\n allocatedArea: z.number(),\n variance: z.number().nullable(),\n})\nexport type PluginSpreadsheetProgramRow = z.infer<\n typeof PluginSpreadsheetProgramRow\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.getProgram} — the area-program\n * dataset {@linkcode PluginProgramSpreadsheetApi.renderProgram} draws. For the\n * canonical summary read, see {@linkcode PluginProgramMetricsApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `units` | `\"ft2\" \\| \"m2\"` | The unit every area in this dataset is reported in |\n * | `rows` | {@linkcode PluginSpreadsheetProgramRow}`[]` | Per-department program rows |\n * | `totalTargetArea` | `number` | Sum of all department target areas |\n * | `totalAllocatedArea` | `number` | Total allocated area |\n * | `generatedAt` | `string` | ISO timestamp of when the dataset was projected |\n */\nexport const PluginProgramSpreadsheetGetProgramResult = z.object({\n units: PluginAreaUnit,\n rows: z.array(PluginSpreadsheetProgramRow),\n totalTargetArea: z.number(),\n totalAllocatedArea: z.number(),\n generatedAt: z.string(),\n})\nexport type PluginProgramSpreadsheetGetProgramResult = z.infer<\n typeof PluginProgramSpreadsheetGetProgramResult\n>\n\n/**\n * One family-aggregated row in the quantity/material takeoff dataset. The takeoff\n * is grouped by object type + category + family (not per element), so each row is\n * a rolled-up quantity for that family.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `objectType` | `string` | Element object type (e.g. `\"Wall\"`, `\"Door\"`, `\"Window\"`) |\n * | `category` | `string` | Element category |\n * | `family` | `string` | Element family the quantity is aggregated over |\n * | `quantity` | `number` | Aggregated quantity in `unit` |\n * | `unit` | `string` | Quantity unit (e.g. `\"m\"` for length, `\"m2\"` for area) |\n */\nexport const PluginSpreadsheetTakeoffRow = z.object({\n objectType: z.string(),\n category: z.string(),\n family: z.string(),\n quantity: z.number(),\n unit: z.string(),\n})\nexport type PluginSpreadsheetTakeoffRow = z.infer<\n typeof PluginSpreadsheetTakeoffRow\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.getTakeoff} — the takeoff dataset\n * {@linkcode PluginProgramSpreadsheetApi.renderTakeoff} draws.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `rows` | {@linkcode PluginSpreadsheetTakeoffRow}`[]` | One row per aggregated object-type/category/family group |\n * | `rowCount` | `number` | Number of rows |\n * | `generatedAt` | `string` | ISO timestamp of when the dataset was read |\n */\nexport const PluginProgramSpreadsheetGetTakeoffResult = z.object({\n rows: z.array(PluginSpreadsheetTakeoffRow),\n rowCount: z.number(),\n generatedAt: z.string(),\n})\nexport type PluginProgramSpreadsheetGetTakeoffResult = z.infer<\n typeof PluginProgramSpreadsheetGetTakeoffResult\n>\n\n// --- createSheet -----------------------------------------------------------\n\n/** Behaviour when {@linkcode PluginProgramSpreadsheetApi.createSheet} targets an existing sheet name. */\nexport const PluginSpreadsheetWhenExists = z.enum([\"reuse\", \"replace\", \"error\"])\nexport type PluginSpreadsheetWhenExists = z.infer<\n typeof PluginSpreadsheetWhenExists\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.createSheet}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string` | The sheet name to create |\n * | `whenExists` | `\"reuse\" \\| \"replace\" \\| \"error\"?` | Behaviour if the name exists (default `\"reuse\"`) |\n */\nexport const PluginProgramSpreadsheetCreateSheetArgs = z.object({\n name: z.string(),\n whenExists: PluginSpreadsheetWhenExists.optional(),\n})\nexport type PluginProgramSpreadsheetCreateSheetArgs = z.infer<\n typeof PluginProgramSpreadsheetCreateSheetArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.createSheet}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | The resolved sheet name |\n * | `replaced` | `boolean` | Whether an existing sheet was replaced/cleared |\n * | `sheetIndex` | `number \\| null` | Zero-based index of the sheet, or `null` if unknown |\n */\nexport const PluginProgramSpreadsheetCreateSheetResult = z.object({\n sheetName: z.string(),\n replaced: z.boolean(),\n sheetIndex: z.number().nullable(),\n})\nexport type PluginProgramSpreadsheetCreateSheetResult = z.infer<\n typeof PluginProgramSpreadsheetCreateSheetResult\n>\n\n// --- setValues -------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.setValues}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | Sheet to write into |\n * | `values` | `cell[][]` | Row-major matrix of values to write |\n * | `startCell` | `string?` | Top-left anchor in A1 notation (default `\"A1\"`) |\n */\nexport const PluginProgramSpreadsheetSetValuesArgs = z.object({\n sheetName: z.string(),\n values: z.array(z.array(PluginSpreadsheetCell)),\n startCell: z.string().optional(),\n})\nexport type PluginProgramSpreadsheetSetValuesArgs = z.infer<\n typeof PluginProgramSpreadsheetSetValuesArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.setValues}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | The sheet that was written |\n * | `startCell` | `string` | The anchor cell values were written from |\n * | `rowCount` | `number` | Number of rows written |\n * | `colCount` | `number` | Widest row's column count |\n */\nexport const PluginProgramSpreadsheetSetValuesResult = z.object({\n sheetName: z.string(),\n startCell: z.string(),\n rowCount: z.number(),\n colCount: z.number(),\n})\nexport type PluginProgramSpreadsheetSetValuesResult = z.infer<\n typeof PluginProgramSpreadsheetSetValuesResult\n>\n\n// --- setFormulas -----------------------------------------------------------\n\n/**\n * A single cell formula for {@linkcode PluginProgramSpreadsheetApi.setFormulas}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `cell` | `string` | Target cell in A1 notation |\n * | `formula` | `string` | Formula expression (a leading `=` is optional) |\n */\nexport const PluginSpreadsheetFormula = z.object({\n cell: z.string(),\n formula: z.string(),\n})\nexport type PluginSpreadsheetFormula = z.infer<typeof PluginSpreadsheetFormula>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.setFormulas}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | Sheet to set formulas on |\n * | `formulas` | {@linkcode PluginSpreadsheetFormula}`[]` | The cell → formula assignments |\n */\nexport const PluginProgramSpreadsheetSetFormulasArgs = z.object({\n sheetName: z.string(),\n formulas: z.array(PluginSpreadsheetFormula),\n})\nexport type PluginProgramSpreadsheetSetFormulasArgs = z.infer<\n typeof PluginProgramSpreadsheetSetFormulasArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.setFormulas}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | The sheet that was written |\n * | `count` | `number` | Number of formulas set |\n */\nexport const PluginProgramSpreadsheetSetFormulasResult = z.object({\n sheetName: z.string(),\n count: z.number(),\n})\nexport type PluginProgramSpreadsheetSetFormulasResult = z.infer<\n typeof PluginProgramSpreadsheetSetFormulasResult\n>\n\n// --- setStyles -------------------------------------------------------------\n\n/** Font weight for a {@linkcode PluginSpreadsheetCellStyle}. */\nexport const PluginSpreadsheetFontWeight = z.enum([\"normal\", \"bold\"])\nexport type PluginSpreadsheetFontWeight = z.infer<\n typeof PluginSpreadsheetFontWeight\n>\n\n/** Font style for a {@linkcode PluginSpreadsheetCellStyle}. */\nexport const PluginSpreadsheetFontStyle = z.enum([\"normal\", \"italic\"])\nexport type PluginSpreadsheetFontStyle = z.infer<\n typeof PluginSpreadsheetFontStyle\n>\n\n/** Horizontal cell alignment for a {@linkcode PluginSpreadsheetCellStyle}. */\nexport const PluginSpreadsheetHorizontalAlign = z.enum([\n \"left\",\n \"center\",\n \"right\",\n \"general\",\n])\nexport type PluginSpreadsheetHorizontalAlign = z.infer<\n typeof PluginSpreadsheetHorizontalAlign\n>\n\n/** Vertical cell alignment for a {@linkcode PluginSpreadsheetCellStyle}. */\nexport const PluginSpreadsheetVerticalAlign = z.enum([\n \"top\",\n \"center\",\n \"bottom\",\n])\nexport type PluginSpreadsheetVerticalAlign = z.infer<\n typeof PluginSpreadsheetVerticalAlign\n>\n\n/**\n * A cell style for {@linkcode PluginProgramSpreadsheetApi.setStyles}. All fields\n * are optional; only the ones provided are applied.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `backColor` | `string?` | Background (fill) color, CSS hex |\n * | `foreColor` | `string?` | Text color, CSS hex |\n * | `font` | `string?` | Full CSS font shorthand (overrides the parts below) |\n * | `fontFamily` | `string?` | Font family |\n * | `fontSize` | `number?` | Font size in px |\n * | `fontWeight` | `\"normal\" \\| \"bold\"?` | Font weight |\n * | `fontStyle` | `\"normal\" \\| \"italic\"?` | Font style |\n * | `formatter` | `string?` | Number/date format string |\n * | `horizontalAlign` | `\"left\" \\| \"center\" \\| \"right\" \\| \"general\"?` | Horizontal alignment |\n * | `verticalAlign` | `\"top\" \\| \"center\" \\| \"bottom\"?` | Vertical alignment |\n */\nexport const PluginSpreadsheetCellStyle = z.object({\n backColor: z.string().optional(),\n foreColor: z.string().optional(),\n font: z.string().optional(),\n fontFamily: z.string().optional(),\n fontSize: z.number().optional(),\n fontWeight: PluginSpreadsheetFontWeight.optional(),\n fontStyle: PluginSpreadsheetFontStyle.optional(),\n formatter: z.string().optional(),\n horizontalAlign: PluginSpreadsheetHorizontalAlign.optional(),\n verticalAlign: PluginSpreadsheetVerticalAlign.optional(),\n})\nexport type PluginSpreadsheetCellStyle = z.infer<\n typeof PluginSpreadsheetCellStyle\n>\n\n/**\n * A range + the style to apply to it, for {@linkcode PluginProgramSpreadsheetApi.setStyles}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `range` | `string` | A1 range to style |\n * | `style` | {@linkcode PluginSpreadsheetCellStyle} | The style to apply |\n */\nexport const PluginSpreadsheetRangeStyle = z.object({\n range: z.string(),\n style: PluginSpreadsheetCellStyle,\n})\nexport type PluginSpreadsheetRangeStyle = z.infer<\n typeof PluginSpreadsheetRangeStyle\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.setStyles}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | Sheet containing the ranges |\n * | `ranges` | {@linkcode PluginSpreadsheetRangeStyle}`[]` | Range → style assignments |\n */\nexport const PluginProgramSpreadsheetSetStylesArgs = z.object({\n sheetName: z.string(),\n ranges: z.array(PluginSpreadsheetRangeStyle),\n})\nexport type PluginProgramSpreadsheetSetStylesArgs = z.infer<\n typeof PluginProgramSpreadsheetSetStylesArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.setStyles}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | The sheet that was styled |\n * | `count` | `number` | Number of ranges styled |\n */\nexport const PluginProgramSpreadsheetSetStylesResult = z.object({\n sheetName: z.string(),\n count: z.number(),\n})\nexport type PluginProgramSpreadsheetSetStylesResult = z.infer<\n typeof PluginProgramSpreadsheetSetStylesResult\n>\n\n// --- mergeCells ------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.mergeCells}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | Sheet containing the range |\n * | `range` | `string` | A1 range to merge into one spanned cell |\n * | `value` | `cell?` | Optional value to set in the merged (top-left) cell |\n */\nexport const PluginProgramSpreadsheetMergeCellsArgs = z.object({\n sheetName: z.string(),\n range: z.string(),\n value: PluginSpreadsheetCell.optional(),\n})\nexport type PluginProgramSpreadsheetMergeCellsArgs = z.infer<\n typeof PluginProgramSpreadsheetMergeCellsArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.mergeCells}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | The sheet that was merged |\n * | `range` | `string` | The range that was merged |\n */\nexport const PluginProgramSpreadsheetMergeCellsResult = z.object({\n sheetName: z.string(),\n range: z.string(),\n})\nexport type PluginProgramSpreadsheetMergeCellsResult = z.infer<\n typeof PluginProgramSpreadsheetMergeCellsResult\n>\n\n// --- addConditionalFormatting ----------------------------------------------\n\n/** Conditional-formatting rule type. Currently only `dataBar`; more are reserved. */\nexport const PluginSpreadsheetConditionalRuleType = z.enum([\"dataBar\"])\nexport type PluginSpreadsheetConditionalRuleType = z.infer<\n typeof PluginSpreadsheetConditionalRuleType\n>\n\n/**\n * A conditional-formatting rule for {@linkcode PluginProgramSpreadsheetApi.addConditionalFormatting}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `type` | `\"dataBar\"` | The rule kind (a proportional in-cell bar) |\n * | `color` | `string?` | Bar color, CSS hex (a default is used when omitted) |\n */\nexport const PluginSpreadsheetConditionalRule = z.object({\n type: PluginSpreadsheetConditionalRuleType,\n color: z.string().optional(),\n})\nexport type PluginSpreadsheetConditionalRule = z.infer<\n typeof PluginSpreadsheetConditionalRule\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.addConditionalFormatting}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | Sheet containing the range |\n * | `range` | `string` | A1 range to format |\n * | `rule` | {@linkcode PluginSpreadsheetConditionalRule} | The conditional-format rule |\n */\nexport const PluginProgramSpreadsheetAddConditionalFormattingArgs = z.object({\n sheetName: z.string(),\n range: z.string(),\n rule: PluginSpreadsheetConditionalRule,\n})\nexport type PluginProgramSpreadsheetAddConditionalFormattingArgs = z.infer<\n typeof PluginProgramSpreadsheetAddConditionalFormattingArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.addConditionalFormatting}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | The sheet that was formatted |\n * | `range` | `string` | The range the rule was applied to |\n * | `created` | `boolean` | Whether a data-bar rule was created (vs a fallback fill) |\n */\nexport const PluginProgramSpreadsheetAddConditionalFormattingResult = z.object({\n sheetName: z.string(),\n range: z.string(),\n created: z.boolean(),\n})\nexport type PluginProgramSpreadsheetAddConditionalFormattingResult = z.infer<\n typeof PluginProgramSpreadsheetAddConditionalFormattingResult\n>\n\n// --- recalculate -----------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.recalculate}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string?` | A sheet to focus before recalculating; omit for the whole workbook |\n */\nexport const PluginProgramSpreadsheetRecalculateArgs = z.object({\n sheetName: z.string().optional(),\n})\nexport type PluginProgramSpreadsheetRecalculateArgs = z.infer<\n typeof PluginProgramSpreadsheetRecalculateArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.recalculate}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `scope` | `\"sheet\" \\| \"workbook\"` | Whether a single sheet was focused or the whole workbook |\n * | `sheetName` | `string \\| null` | The focused sheet, or `null` for a workbook-wide recompute |\n */\nexport const PluginProgramSpreadsheetRecalculateResult = z.object({\n scope: z.enum([\"sheet\", \"workbook\"]),\n sheetName: z.string().nullable(),\n})\nexport type PluginProgramSpreadsheetRecalculateResult = z.infer<\n typeof PluginProgramSpreadsheetRecalculateResult\n>\n\n// --- transaction -----------------------------------------------------------\n\n/** A batchable operation name for {@linkcode PluginProgramSpreadsheetApi.transaction}. */\nexport const PluginSpreadsheetTransactionMethod = z.enum([\n \"createSheet\",\n \"setValues\",\n \"setFormulas\",\n \"setStyles\",\n \"mergeCells\",\n])\nexport type PluginSpreadsheetTransactionMethod = z.infer<\n typeof PluginSpreadsheetTransactionMethod\n>\n\n/**\n * One operation within a {@linkcode PluginProgramSpreadsheetApi.transaction}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `method` | {@linkcode PluginSpreadsheetTransactionMethod} | The batchable method to run |\n * | `args` | `unknown` | The `method`'s own arguments object |\n */\nexport const PluginSpreadsheetTransactionOp = z.object({\n method: PluginSpreadsheetTransactionMethod,\n args: z.unknown(),\n})\nexport type PluginSpreadsheetTransactionOp = z.infer<\n typeof PluginSpreadsheetTransactionOp\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.transaction}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `operations` | {@linkcode PluginSpreadsheetTransactionOp}`[]` | The operations to run in order |\n * | `label` | `string?` | Undo-history label for the batch |\n */\nexport const PluginProgramSpreadsheetTransactionArgs = z.object({\n operations: z.array(PluginSpreadsheetTransactionOp),\n label: z.string().optional(),\n})\nexport type PluginProgramSpreadsheetTransactionArgs = z.infer<\n typeof PluginProgramSpreadsheetTransactionArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.transaction}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `label` | `string` | The undo-history label used |\n * | `operationCount` | `number` | Number of operations run |\n * | `results` | `unknown[]` | Each operation's result, in order |\n */\nexport const PluginProgramSpreadsheetTransactionResult = z.object({\n label: z.string(),\n operationCount: z.number(),\n results: z.array(z.unknown()),\n})\nexport type PluginProgramSpreadsheetTransactionResult = z.infer<\n typeof PluginProgramSpreadsheetTransactionResult\n>\n\n// --- runScript -------------------------------------------------------------\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.runScript}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `script` | `string` | Script source, run against a sandboxed `workbook` facade |\n */\nexport const PluginProgramSpreadsheetRunScriptArgs = z.object({\n script: z.string(),\n})\nexport type PluginProgramSpreadsheetRunScriptArgs = z.infer<\n typeof PluginProgramSpreadsheetRunScriptArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.runScript}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `result` | `unknown` | The script's return value (`null` when it returns nothing) |\n */\nexport const PluginProgramSpreadsheetRunScriptResult = z.object({\n result: z.unknown(),\n})\nexport type PluginProgramSpreadsheetRunScriptResult = z.infer<\n typeof PluginProgramSpreadsheetRunScriptResult\n>\n\n// --- getAuditLog -----------------------------------------------------------\n\n/** Status of an audit-log entry. */\nexport const PluginSpreadsheetAuditStatus = z.enum([\"success\", \"error\"])\nexport type PluginSpreadsheetAuditStatus = z.infer<\n typeof PluginSpreadsheetAuditStatus\n>\n\n/**\n * One entry in the program-spreadsheet audit log.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Entry id |\n * | `pluginId` | `string` | Id of the plugin that performed the operation |\n * | `method` | `string` | The API method invoked |\n * | `label` | `string?` | Optional operation label |\n * | `sheetName` | `string?` | The sheet the operation targeted, if any |\n * | `timestamp` | `string` | ISO timestamp |\n * | `status` | `\"success\" \\| \"error\"` | Whether the operation succeeded |\n * | `summary` | `string?` | Short human-readable summary |\n */\nexport const PluginSpreadsheetAuditEntry = z.object({\n id: z.string(),\n pluginId: z.string(),\n method: z.string(),\n label: z.string().optional(),\n sheetName: z.string().optional(),\n timestamp: z.string(),\n status: PluginSpreadsheetAuditStatus,\n summary: z.string().optional(),\n})\nexport type PluginSpreadsheetAuditEntry = z.infer<\n typeof PluginSpreadsheetAuditEntry\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetApi.getAuditLog}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `limit` | `number?` | Max entries to return (clamped 1–100, default 20) |\n */\nexport const PluginProgramSpreadsheetGetAuditLogArgs = z.object({\n limit: z.number().optional(),\n})\nexport type PluginProgramSpreadsheetGetAuditLogArgs = z.infer<\n typeof PluginProgramSpreadsheetGetAuditLogArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.getAuditLog}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `entries` | {@linkcode PluginSpreadsheetAuditEntry}`[]` | Recent audit entries, newest first |\n */\nexport const PluginProgramSpreadsheetGetAuditLogResult = z.object({\n entries: z.array(PluginSpreadsheetAuditEntry),\n})\nexport type PluginProgramSpreadsheetGetAuditLogResult = z.infer<\n typeof PluginProgramSpreadsheetGetAuditLogResult\n>\n\n// --- ping ------------------------------------------------------------------\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetApi.ping}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `pong` | `boolean` | `true` when the program-mode spreadsheet bridge is reachable |\n */\nexport const PluginProgramSpreadsheetPingResult = z.object({\n pong: z.boolean(),\n})\nexport type PluginProgramSpreadsheetPingResult = z.infer<\n typeof PluginProgramSpreadsheetPingResult\n>\n\n// --- templates.* -----------------------------------------------------------\n\n/** The visibility scope of a saved template. */\nexport const PluginSpreadsheetTemplateScope = z.enum([\"project\", \"global\"])\nexport type PluginSpreadsheetTemplateScope = z.infer<\n typeof PluginSpreadsheetTemplateScope\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetTemplatesApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string` | Template name (re-saving the same name overwrites it) |\n * | `sheetName` | `string` | The source sheet to capture |\n * | `scope` | `\"project\" \\| \"global\"?` | Template scope (default `\"project\"`) |\n */\nexport const PluginProgramSpreadsheetTemplatesCreateArgs = z.object({\n name: z.string(),\n sheetName: z.string(),\n scope: PluginSpreadsheetTemplateScope.optional(),\n})\nexport type PluginProgramSpreadsheetTemplatesCreateArgs = z.infer<\n typeof PluginProgramSpreadsheetTemplatesCreateArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetTemplatesApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | The new template's id |\n * | `name` | `string` | The template name |\n * | `scope` | `\"project\" \\| \"global\"` | The template scope |\n * | `sheetName` | `string` | The source sheet captured |\n */\nexport const PluginProgramSpreadsheetTemplatesCreateResult = z.object({\n id: z.string(),\n name: z.string(),\n scope: PluginSpreadsheetTemplateScope,\n sheetName: z.string(),\n})\nexport type PluginProgramSpreadsheetTemplatesCreateResult = z.infer<\n typeof PluginProgramSpreadsheetTemplatesCreateResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetTemplatesApi.apply}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string` | The template to apply |\n * | `targetSheetName` | `string` | The sheet to create/replace from the template |\n */\nexport const PluginProgramSpreadsheetTemplatesApplyArgs = z.object({\n name: z.string(),\n targetSheetName: z.string(),\n})\nexport type PluginProgramSpreadsheetTemplatesApplyArgs = z.infer<\n typeof PluginProgramSpreadsheetTemplatesApplyArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetTemplatesApi.apply}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string` | The template that was applied |\n * | `targetSheetName` | `string` | The sheet it was applied to |\n */\nexport const PluginProgramSpreadsheetTemplatesApplyResult = z.object({\n name: z.string(),\n targetSheetName: z.string(),\n})\nexport type PluginProgramSpreadsheetTemplatesApplyResult = z.infer<\n typeof PluginProgramSpreadsheetTemplatesApplyResult\n>\n\n// --- bindings.* ------------------------------------------------------------\n\n/**\n * A binding's data source. Currently only the takeoff dataset; `program` is\n * reserved for a future source.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `dataset` | `\"takeoff\"` | The dataset the binding pulls from |\n */\nexport const PluginSpreadsheetBindingSource = z.object({\n dataset: z.enum([\"takeoff\"]),\n})\nexport type PluginSpreadsheetBindingSource = z.infer<\n typeof PluginSpreadsheetBindingSource\n>\n\n/** How a binding refresh writes into its target range. Currently only `replaceRange`. */\nexport const PluginSpreadsheetBindingMode = z.enum([\"replaceRange\"])\nexport type PluginSpreadsheetBindingMode = z.infer<\n typeof PluginSpreadsheetBindingMode\n>\n\n/**\n * A binding's target range, for {@linkcode PluginProgramSpreadsheetBindingsApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetName` | `string` | The sheet to write into |\n * | `startCell` | `string?` | Top-left anchor in A1 notation (default `\"A1\"`) |\n */\nexport const PluginSpreadsheetBindingTarget = z.object({\n sheetName: z.string(),\n startCell: z.string().optional(),\n})\nexport type PluginSpreadsheetBindingTarget = z.infer<\n typeof PluginSpreadsheetBindingTarget\n>\n\n/**\n * A stored data binding.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Binding id |\n * | `name` | `string` | Binding name (unique per workbook) |\n * | `pluginId` | `string` | Id of the plugin that owns the binding |\n * | `source` | {@linkcode PluginSpreadsheetBindingSource} | The bound dataset |\n * | `target` | `{ sheetName: string; startCell: string }` | The resolved target range anchor |\n * | `mode` | {@linkcode PluginSpreadsheetBindingMode} | How a refresh writes into the target |\n * | `createdAt` | `string` | ISO creation timestamp |\n * | `updatedAt` | `string` | ISO last-refresh timestamp |\n */\nexport const PluginSpreadsheetBinding = z.object({\n id: z.string(),\n name: z.string(),\n pluginId: z.string(),\n source: PluginSpreadsheetBindingSource,\n target: z.object({\n sheetName: z.string(),\n startCell: z.string(),\n }),\n mode: PluginSpreadsheetBindingMode,\n createdAt: z.string(),\n updatedAt: z.string(),\n})\nexport type PluginSpreadsheetBinding = z.infer<typeof PluginSpreadsheetBinding>\n\n/**\n * The outcome of refreshing a single binding.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | The refreshed binding's id |\n * | `name` | `string` | The refreshed binding's name |\n * | `sheetName` | `string` | The sheet that was rewritten |\n * | `rowCount` | `number` | Number of rows written |\n */\nexport const PluginSpreadsheetBindingRefresh = z.object({\n id: z.string(),\n name: z.string(),\n sheetName: z.string(),\n rowCount: z.number(),\n})\nexport type PluginSpreadsheetBindingRefresh = z.infer<\n typeof PluginSpreadsheetBindingRefresh\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetBindingsApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string` | Binding name (re-using a name overwrites it) |\n * | `source` | {@linkcode PluginSpreadsheetBindingSource} | The dataset to bind |\n * | `target` | {@linkcode PluginSpreadsheetBindingTarget} | The target sheet range |\n * | `mode` | {@linkcode PluginSpreadsheetBindingMode}`?` | How a refresh writes (default `\"replaceRange\"`) |\n */\nexport const PluginProgramSpreadsheetBindingsCreateArgs = z.object({\n name: z.string(),\n source: PluginSpreadsheetBindingSource,\n target: PluginSpreadsheetBindingTarget,\n mode: PluginSpreadsheetBindingMode.optional(),\n})\nexport type PluginProgramSpreadsheetBindingsCreateArgs = z.infer<\n typeof PluginProgramSpreadsheetBindingsCreateArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetBindingsApi.create} — the stored\n * {@linkcode PluginSpreadsheetBinding} plus the initial `refresh` outcome.\n */\nexport const PluginProgramSpreadsheetBindingsCreateResult =\n PluginSpreadsheetBinding.extend({\n refresh: PluginSpreadsheetBindingRefresh,\n })\nexport type PluginProgramSpreadsheetBindingsCreateResult = z.infer<\n typeof PluginProgramSpreadsheetBindingsCreateResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramSpreadsheetBindingsApi.refresh}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string?` | The binding to refresh; omit to refresh every binding |\n */\nexport const PluginProgramSpreadsheetBindingsRefreshArgs = z.object({\n name: z.string().optional(),\n})\nexport type PluginProgramSpreadsheetBindingsRefreshArgs = z.infer<\n typeof PluginProgramSpreadsheetBindingsRefreshArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetBindingsApi.refresh}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `refreshed` | {@linkcode PluginSpreadsheetBindingRefresh}`[]` | One entry per binding refreshed |\n */\nexport const PluginProgramSpreadsheetBindingsRefreshResult = z.object({\n refreshed: z.array(PluginSpreadsheetBindingRefresh),\n})\nexport type PluginProgramSpreadsheetBindingsRefreshResult = z.infer<\n typeof PluginProgramSpreadsheetBindingsRefreshResult\n>\n\n/**\n * Result of {@linkcode PluginProgramSpreadsheetBindingsApi.list}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `bindings` | {@linkcode PluginSpreadsheetBinding}`[]` | Every stored binding |\n */\nexport const PluginProgramSpreadsheetBindingsListResult = z.object({\n bindings: z.array(PluginSpreadsheetBinding),\n})\nexport type PluginProgramSpreadsheetBindingsListResult = z.infer<\n typeof PluginProgramSpreadsheetBindingsListResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\nimport { PluginAreaUnit } from \"./metrics\"\n\n/**\n * Program site — read the planning context of the project's site/plot.\n *\n * The **site** is the set of plot/parcel footprints the program is planned\n * against: their total area, per-parcel footprints (in scene XZ coordinates),\n * and — when the project is geo-located on terrain — their geographic\n * (latitude/longitude) rings. This is the program-planning view of the site;\n * zoning numbers (setbacks, FAR/FSI, height limits) live in the site-analysis\n * sheet and are not read here.\n *\n * All methods are reads: they return plain records and never throw — `get`\n * returns an empty snapshot (zero totals) when there is no site, and the `list`\n * methods return `[]`.\n *\n * Accessed via `snaptrude.program.site`.\n */\nexport abstract class PluginProgramSiteApi {\n constructor() {}\n\n /**\n * Get a snapshot of the project site.\n *\n * @returns A {@linkcode PluginProgramSiteSnapshot} with the total site area,\n * parcel count, and each parcel's footprint. Empty (zero totals, no\n * parcels) when the project has no site.\n *\n * @examplePrompt What is my total site area?\n * @examplePrompt Give me a summary of the site\n * @examplePrompt How many site parcels are on the canvas?\n * @examplePrompt Show the site footprint and its area\n * @examplePrompt How big is the plot I'm building on?\n *\n * # Example\n * ```ts\n * const site = await snaptrude.program.site.get()\n * console.log(`${site.totalArea} ${site.units} across ${site.polygonCount} parcels`)\n * ```\n */\n public abstract get(): PluginApiReturn<PluginProgramSiteSnapshot>\n\n /**\n * Get just the total site area.\n *\n * A fast single-metric read — the same number as\n * {@linkcode PluginProgramSiteSnapshot.totalArea}, without computing the\n * per-parcel footprints.\n *\n * @returns A {@linkcode PluginProgramSiteAreaResult} with the total `area` and\n * its `units` (`0` when there is no site).\n *\n * @examplePrompt What's the total site area?\n * @examplePrompt How big is my plot in square metres?\n * @examplePrompt Total parcel area on the site\n *\n * # Example\n * ```ts\n * const { area, units } = await snaptrude.program.site.getArea()\n * ```\n */\n public abstract getArea(): PluginApiReturn<PluginProgramSiteAreaResult>\n\n /**\n * List the site parcels with their footprints (in scene coordinates).\n *\n * @returns A {@linkcode PluginProgramSiteListPolygonsResult} with each parcel's\n * id, area, label, and 2D footprint (XZ ground-plane points). Empty when the\n * project has no site.\n *\n * @examplePrompt List every site parcel\n * @examplePrompt Show me each plot's footprint\n * @examplePrompt Which site parcels are largest?\n * @examplePrompt Get the boundary points of the site polygons\n *\n * # Example\n * ```ts\n * const { polygons, units } = await snaptrude.program.site.listPolygons()\n * for (const p of polygons) console.log(p.label, p.area, units, p.footprint.length)\n * ```\n */\n public abstract listPolygons(): PluginApiReturn<PluginProgramSiteListPolygonsResult>\n\n /**\n * List the site parcels as geographic latitude/longitude rings.\n *\n * Only available when the project is geo-located on terrain; returns `[]` (no\n * rings) otherwise. Use {@linkcode PluginProgramSiteApi.listPolygons} for the\n * scene-coordinate footprints that are always available.\n *\n * @returns A {@linkcode PluginProgramSiteListGeoPolygonsResult} with one ring\n * of `{ lat, lng, alt }` points per parcel.\n *\n * @examplePrompt Give me the site polygons in latitude and longitude\n * @examplePrompt Export the plot boundary as geo-coordinates\n * @examplePrompt Where is the site located geographically?\n * @examplePrompt Get the site parcels as lat/long rings\n *\n * # Example\n * ```ts\n * const { polygons } = await snaptrude.program.site.listGeoPolygons()\n * const firstRing = polygons[0] // [{ lat, lng, alt }, ...]\n * ```\n */\n public abstract listGeoPolygons(): PluginApiReturn<PluginProgramSiteListGeoPolygonsResult>\n\n /**\n * Get the geo-referenced terrain context of the site.\n *\n * The map center and bounds, the terrain size in metres, the effective zoom,\n * and each parcel's geographic footprint and area — the context used for site\n * analysis. Returns `null` when the project is not geo-located on terrain.\n *\n * @returns A {@linkcode PluginProgramSiteContext}, or `null`.\n *\n * @examplePrompt What's the site's map center and bounds?\n * @examplePrompt How wide is the terrain in metres?\n * @examplePrompt Give me the parcel geometry and areas\n * @examplePrompt Where is the site located on the map?\n *\n * # Example\n * ```ts\n * const ctx = await snaptrude.program.site.getContext()\n * if (ctx) console.log(ctx.center, ctx.widthInM)\n * ```\n */\n public abstract getContext(): PluginApiReturn<PluginProgramSiteContextResult>\n}\n\n/**\n * A 2D ground-plane point of a site parcel footprint, in scene coordinates\n * (metres on the project's XZ plane).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `x` | `number` | X coordinate (scene metres) |\n * | `z` | `number` | Z coordinate (scene metres) |\n */\nexport const PluginSiteFootprintPoint = z.object({\n x: z.number(),\n z: z.number(),\n})\nexport type PluginSiteFootprintPoint = z.infer<typeof PluginSiteFootprintPoint>\n\n/**\n * A geographic point of a site parcel ring (WGS84).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `lat` | `number` | Latitude (degrees) |\n * | `lng` | `number` | Longitude (degrees) |\n * | `alt` | `number` | Altitude (metres) |\n */\nexport const PluginSiteGeoPoint = z.object({\n lat: z.number(),\n lng: z.number(),\n alt: z.number(),\n})\nexport type PluginSiteGeoPoint = z.infer<typeof PluginSiteGeoPoint>\n\n/**\n * A single site parcel/polygon. Its `area` is in the enclosing result's `units`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Unique parcel/component id |\n * | `area` | `number` | Footprint area, in the result's `units` |\n * | `label` | `string` | Parcel label / room type (e.g. `\"site\"`) |\n * | `footprint` | {@linkcode PluginSiteFootprintPoint}`[]` | 2D ground-plane boundary points |\n */\nexport const PluginSitePolygon = z.object({\n id: z.string(),\n area: z.number(),\n label: z.string(),\n footprint: z.array(PluginSiteFootprintPoint),\n})\nexport type PluginSitePolygon = z.infer<typeof PluginSitePolygon>\n\n/**\n * Result of {@linkcode PluginProgramSiteApi.get}. Per the area-units convention,\n * `units` sits on this snapshot and every `area` below is reported in it.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `units` | `\"ft2\" \\| \"m2\"` | The unit all areas in this snapshot are reported in |\n * | `totalArea` | `number` | Total area of all site parcels |\n * | `polygonCount` | `number` | Number of site parcels |\n * | `polygons` | {@linkcode PluginSitePolygon}`[]` | Each site parcel with its footprint |\n */\nexport const PluginProgramSiteSnapshot = z.object({\n units: PluginAreaUnit,\n totalArea: z.number(),\n polygonCount: z.number(),\n polygons: z.array(PluginSitePolygon),\n})\nexport type PluginProgramSiteSnapshot = z.infer<\n typeof PluginProgramSiteSnapshot\n>\n\n/**\n * Result of {@linkcode PluginProgramSiteApi.getArea}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `units` | `\"ft2\" \\| \"m2\"` | The unit `area` is reported in |\n * | `area` | `number` | Total site area |\n */\nexport const PluginProgramSiteAreaResult = z.object({\n units: PluginAreaUnit,\n area: z.number(),\n})\nexport type PluginProgramSiteAreaResult = z.infer<\n typeof PluginProgramSiteAreaResult\n>\n\n/**\n * Result of {@linkcode PluginProgramSiteApi.listPolygons}. `units` sits on the\n * response; each parcel's `area` is in it.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `units` | `\"ft2\" \\| \"m2\"` | The unit every parcel `area` is reported in |\n * | `polygons` | {@linkcode PluginSitePolygon}`[]` | All site parcels |\n */\nexport const PluginProgramSiteListPolygonsResult = z.object({\n units: PluginAreaUnit,\n polygons: z.array(PluginSitePolygon),\n})\nexport type PluginProgramSiteListPolygonsResult = z.infer<\n typeof PluginProgramSiteListPolygonsResult\n>\n\n/**\n * Result of {@linkcode PluginProgramSiteApi.listGeoPolygons} — one ring of\n * geographic points per parcel (`[]` when the project is not geo-located).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `polygons` | {@linkcode PluginSiteGeoPoint}`[][]` | One ring per parcel; each ring is a list of geographic points |\n */\nexport const PluginProgramSiteListGeoPolygonsResult = z.object({\n polygons: z.array(z.array(PluginSiteGeoPoint)),\n})\nexport type PluginProgramSiteListGeoPolygonsResult = z.infer<\n typeof PluginProgramSiteListGeoPolygonsResult\n>\n\n/**\n * A geographic latitude/longitude point (no altitude).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `lat` | `number` | Latitude (degrees) |\n * | `lng` | `number` | Longitude (degrees) |\n */\nexport const PluginSiteLatLng = z.object({\n lat: z.number(),\n lng: z.number(),\n})\nexport type PluginSiteLatLng = z.infer<typeof PluginSiteLatLng>\n\n/**\n * Geographic bounds of the site terrain.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `north` | `number` | North latitude |\n * | `south` | `number` | South latitude |\n * | `east` | `number` | East longitude |\n * | `west` | `number` | West longitude |\n */\nexport const PluginSiteBounds = z.object({\n north: z.number(),\n south: z.number(),\n east: z.number(),\n west: z.number(),\n})\nexport type PluginSiteBounds = z.infer<typeof PluginSiteBounds>\n\n/**\n * A site parcel in the terrain context — geographic footprint and area.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `footprint` | {@linkcode PluginSiteLatLng}`[]` | Geographic boundary points |\n * | `area` | `number` | Parcel area (project area units) |\n */\nexport const PluginSiteContextParcel = z.object({\n footprint: z.array(PluginSiteLatLng),\n area: z.number(),\n})\nexport type PluginSiteContextParcel = z.infer<typeof PluginSiteContextParcel>\n\n/**\n * The geo-referenced terrain context of the site.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `center` | {@linkcode PluginSiteLatLng} | Map center |\n * | `bounds` | {@linkcode PluginSiteBounds} | Terrain bounds |\n * | `widthInM` | `number` | Terrain width in metres |\n * | `heightInM` | `number` | Terrain height in metres |\n * | `zoom` | `number` | Effective map zoom |\n * | `parcels` | {@linkcode PluginSiteContextParcel}`[]` | Site parcels with geographic footprints |\n */\nexport const PluginProgramSiteContext = z.object({\n center: PluginSiteLatLng,\n bounds: PluginSiteBounds,\n widthInM: z.number(),\n heightInM: z.number(),\n zoom: z.number(),\n parcels: z.array(PluginSiteContextParcel),\n})\nexport type PluginProgramSiteContext = z.infer<typeof PluginProgramSiteContext>\n\n/**\n * Result of {@linkcode PluginProgramSiteApi.getContext} — the terrain context, or\n * `null` when the project is not geo-located.\n */\nexport const PluginProgramSiteContextResult =\n PluginProgramSiteContext.nullable()\nexport type PluginProgramSiteContextResult = z.infer<\n typeof PluginProgramSiteContextResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Program cores — the building's vertical-circulation cores (lift / stair / shaft\n * shells).\n *\n * Read the cores in the scene, test whether a space is a core, and trigger core\n * generation from a layout. `create` is a **thin trigger**: the program hands a\n * core layout to the core-generation engine, which authors the geometry — the\n * core geometry itself is owned by the geometry layer, not here (the exact\n * layout ↔ engine payload is coordinated with the geometry owner).\n *\n * `list`/`isCore` are reads; `create` triggers generation.\n *\n * Accessed via `snaptrude.program.cores`.\n */\nexport abstract class PluginProgramCoresApi {\n constructor() {}\n\n /**\n * List the cores currently in the building.\n *\n * @returns A {@linkcode PluginProgramCoresListResult} with each core's id,\n * core group, and storey (empty when there are none).\n *\n * @examplePrompt List the cores in the building\n * @examplePrompt How many cores are placed?\n * @examplePrompt Show me the lift and stair cores\n * @examplePrompt Which storeys have cores?\n *\n * # Example\n * ```ts\n * const { cores } = await snaptrude.program.cores.list()\n * ```\n */\n public abstract list(): PluginApiReturn<PluginProgramCoresListResult>\n\n /**\n * Test whether a space is a circulation core element.\n *\n * @param id - The id of the space to test.\n * @returns `true` if the space is a core element.\n *\n * @examplePrompt Is this space a core?\n * @examplePrompt Does this mass belong to the core?\n * @examplePrompt Check if space sp_1 is a circulation core\n *\n * # Example\n * ```ts\n * const isCore = await snaptrude.program.cores.isCore(\"sp_1\")\n * ```\n */\n public abstract isCore(id: string): PluginApiReturn<boolean>\n\n /**\n * Generate core geometry from a layout (thin trigger).\n *\n * Hands the core layout to the core-generation engine and returns how many core\n * elements were created. The geometry is authored by the engine, not here.\n * _(Authored ahead — optional until the host's geometry adapter lands; the\n * reads {@linkcode PluginProgramCoresApi.list}/{@linkcode PluginProgramCoresApi.isCore}\n * are live.)_\n *\n * @param cores - The {@linkcode PluginProgramCoreSpec} layout of cores to\n * generate.\n * @param lengthUnit - Unit of the spec dimensions (default project unit).\n * @returns A {@linkcode PluginProgramCoresCreateResult} with the created count.\n * @throws If the layout could not be realized.\n *\n * @examplePrompt Generate the building cores from this layout\n * @examplePrompt Place the elevator and stair cores\n * @examplePrompt Create the service core shells\n *\n * # Example\n * ```ts\n * await snaptrude.program.cores.create([\n * { type: \"lift\", position: { x: 0, y: 0, z: 0 }, width: 3, depth: 4 },\n * ])\n * ```\n */\n public create?: (\n cores: PluginProgramCoreSpec[],\n lengthUnit?: \"mm\" | \"m\" | \"ft\",\n ) => PluginApiReturn<PluginProgramCoresCreateResult>\n}\n\n/**\n * A circulation core element in the building.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Component id of the core element |\n * | `groupId` | `string` | Id of the core group this element belongs to |\n * | `storey` | `number` | Storey (floor number) the element sits on |\n */\nexport const PluginProgramCore = z.object({\n id: z.string(),\n groupId: z.string(),\n storey: z.number(),\n})\nexport type PluginProgramCore = z.infer<typeof PluginProgramCore>\n\n/** Result of {@linkcode PluginProgramCoresApi.list}. */\nexport const PluginProgramCoresListResult = z.object({\n cores: z.array(PluginProgramCore),\n})\nexport type PluginProgramCoresListResult = z.infer<\n typeof PluginProgramCoresListResult\n>\n\n/** Arguments for {@linkcode PluginProgramCoresApi.isCore}. */\nexport const PluginProgramCoresIsCoreArgs = z.object({\n id: z.string(),\n})\nexport type PluginProgramCoresIsCoreArgs = z.infer<\n typeof PluginProgramCoresIsCoreArgs\n>\n\n/**\n * One core to generate. The geometry layer interprets this layout (the exact\n * fields are coordinated with the geometry owner).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `type` | `string \\| undefined` | Core kind (e.g. `\"lift\"`, `\"stair\"`, `\"shaft\"`) |\n * | `position` | `{ x; y; z }` | Base position of the core |\n * | `width` | `number` | Core width, in `lengthUnit` |\n * | `depth` | `number` | Core depth, in `lengthUnit` |\n * | `fromStorey` | `number \\| undefined` | First storey the core spans |\n * | `toStorey` | `number \\| undefined` | Last storey the core spans |\n */\nexport const PluginProgramCoreSpec = z.object({\n type: z.string().optional(),\n position: z.object({ x: z.number(), y: z.number(), z: z.number() }),\n width: z.number(),\n depth: z.number(),\n fromStorey: z.number().optional(),\n toStorey: z.number().optional(),\n})\nexport type PluginProgramCoreSpec = z.infer<typeof PluginProgramCoreSpec>\n\n/**\n * Arguments for {@linkcode PluginProgramCoresApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `cores` | {@linkcode PluginProgramCoreSpec}`[]` | The cores to generate |\n * | `lengthUnit` | `\"mm\" \\| \"m\" \\| \"ft\" \\| undefined` | Unit of the spec dimensions (default project unit) |\n */\nexport const PluginProgramCoresCreateArgs = z.object({\n cores: z.array(PluginProgramCoreSpec),\n lengthUnit: z.enum([\"mm\", \"m\", \"ft\"]).optional(),\n})\nexport type PluginProgramCoresCreateArgs = z.infer<\n typeof PluginProgramCoresCreateArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramCoresApi.create}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `createdCount` | `number` | Number of core elements created |\n */\nexport const PluginProgramCoresCreateResult = z.object({\n createdCount: z.number(),\n})\nexport type PluginProgramCoresCreateResult = z.infer<\n typeof PluginProgramCoresCreateResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Program classification — the catalog of space-classification options, and a\n * space's display tags.\n *\n * Only the genuinely program-specific reads live here: the selectable\n * space-type / area-class / mass-type options, and a space's tags for display.\n * Reading or changing a *single space's* classification (its type, label, area\n * class, or department) is done through the space reads/writes, not duplicated\n * here. Tag definitions are managed elsewhere — these methods are display-only.\n *\n * Both methods are reads.\n *\n * Accessed via `snaptrude.program.classification`.\n */\nexport abstract class PluginProgramClassificationApi {\n constructor() {}\n\n /**\n * List the selectable classification options for spaces.\n *\n * The static catalog (project-independent) of space types, area classes, and\n * mass types a space can be classified as.\n *\n * @returns A {@linkcode PluginProgramClassificationTypesResult} with the\n * `spaceTypes`, `areaClasses`, and `massTypes` option lists.\n *\n * @examplePrompt What space types can I assign?\n * @examplePrompt List the available area classifications\n * @examplePrompt What classification options exist?\n * @examplePrompt Show me the valid space-type values\n *\n * # Example\n * ```ts\n * const { spaceTypes, areaClasses } = await snaptrude.program.classification.listTypes()\n * ```\n */\n public abstract listTypes(): PluginApiReturn<PluginProgramClassificationTypesResult>\n\n /**\n * List a space's tags for display, grouped by category.\n *\n * @param id - The id of the space whose tags to read.\n * @returns A {@linkcode PluginProgramClassificationTagsResult} with the space's\n * `tagIds` and `tagsByCategory`.\n *\n * @examplePrompt What tags are on this space?\n * @examplePrompt Show the tags grouped by category for sp_4\n * @examplePrompt List this room's display tags\n * @examplePrompt Which tags does this space have?\n *\n * # Example\n * ```ts\n * const { tagsByCategory } = await snaptrude.program.classification.listTags(\"sp_4\")\n * ```\n */\n public abstract listTags(\n id: string,\n ): PluginApiReturn<PluginProgramClassificationTagsResult>\n}\n\n/**\n * A selectable classification option.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `value` | `string` | Stored value |\n * | `label` | `string` | Display label |\n */\nexport const PluginClassificationOption = z.object({\n value: z.string(),\n label: z.string(),\n})\nexport type PluginClassificationOption = z.infer<\n typeof PluginClassificationOption\n>\n\n/**\n * Result of {@linkcode PluginProgramClassificationApi.listTypes}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `spaceTypes` | {@linkcode PluginClassificationOption}`[]` | Selectable space types |\n * | `areaClasses` | {@linkcode PluginClassificationOption}`[]` | Selectable area classes (NET/GROSS/EXCLUDED) |\n * | `massTypes` | {@linkcode PluginClassificationOption}`[]` | Selectable mass/object types |\n */\nexport const PluginProgramClassificationTypesResult = z.object({\n spaceTypes: z.array(PluginClassificationOption),\n areaClasses: z.array(PluginClassificationOption),\n massTypes: z.array(PluginClassificationOption),\n})\nexport type PluginProgramClassificationTypesResult = z.infer<\n typeof PluginProgramClassificationTypesResult\n>\n\n/** Arguments for {@linkcode PluginProgramClassificationApi.listTags}. */\nexport const PluginProgramClassificationListTagsArgs = z.object({\n id: z.string(),\n})\nexport type PluginProgramClassificationListTagsArgs = z.infer<\n typeof PluginProgramClassificationListTagsArgs\n>\n\n/**\n * A display tag on a space.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `tagId` | `string` | Tag id |\n * | `tagName` | `string` | Tag display name |\n * | `color` | `string` | CSS hex color string |\n * | `categoryId` | `string` | Id of the tag's category |\n */\nexport const PluginSpaceTag = z.object({\n tagId: z.string(),\n tagName: z.string(),\n color: z.string(),\n categoryId: z.string(),\n})\nexport type PluginSpaceTag = z.infer<typeof PluginSpaceTag>\n\n/**\n * Result of {@linkcode PluginProgramClassificationApi.listTags}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `tagIds` | `string[]` | All tag ids on the space |\n * | `tagsByCategory` | `Record<string, `{@linkcode PluginSpaceTag}`>` | Tags keyed by category name |\n */\nexport const PluginProgramClassificationTagsResult = z.object({\n tagIds: z.array(z.string()),\n tagsByCategory: z.record(z.string(), PluginSpaceTag),\n})\nexport type PluginProgramClassificationTagsResult = z.infer<\n typeof PluginProgramClassificationTagsResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\nimport { PluginAreaUnit } from \"./metrics\"\nimport { ComponentHandle } from \"../../handles\"\n\n/**\n * Program areas — the FAR / built-up-area rollup for the active program.\n *\n * This is the zoning-compliance lens on the model: carpet / built-up / excluded\n * area totals, the site area, and the achieved-vs-target **FAR** (Floor Area\n * Ratio). It complements {@linkcode PluginProgramMetricsApi}, which is the\n * department-allocation lens (targets vs allocated area per department); this\n * namespace is the whole-program area/FAR summary and its groupings.\n *\n * `achievedFar` is **derived and read-only** — computed from built-up area and\n * site area. `targetFar` is the goal you set (via {@linkcode\n * PluginProgramAreasApi.update}); the two are the same ratio, one measured and\n * one intended. The surface speaks **FAR only** — there is no FSI alias.\n *\n * Reads return plain records and never throw. The write member typed as optional\n * (`?`) is **authored ahead of the host** — declared so plugins and codegen can\n * see the shape, but kept out of the discovery manifest until the host lands it\n * (at which point it is promoted to a required `abstract` member).\n *\n * Accessed via `snaptrude.program.areas`.\n */\nexport abstract class PluginProgramAreasApi {\n constructor() {}\n\n /**\n * Get the program area summary.\n *\n * Returns the whole-program totals — carpet / built-up / excluded area, site\n * area, and achieved vs target FAR — with the area unit they are reported in.\n *\n * @returns A {@linkcode PluginProgramAreaSummary}. `achievedFar` is `null` when\n * the site area or target FAR is not set.\n *\n * @examplePrompt What's my FAR right now?\n * @examplePrompt Give me the program area summary\n * @examplePrompt How much built-up area have I used against the site area?\n * @examplePrompt Am I within my FAR target?\n *\n * # Example\n * ```ts\n * const s = await snaptrude.program.areas.get()\n * console.log(s.builtUp, s.siteArea, s.achievedFar, s.targetFar, s.areaUnit)\n * ```\n */\n public abstract get(): PluginApiReturn<PluginProgramAreasGetResult>\n\n /**\n * List the program area rollup grouped by a facet.\n *\n * Breaks the program's area totals into buckets — by label, storey, building,\n * department, or tag category.\n *\n * @param groupBy - The facet to group by (a {@linkcode PluginProgramAreaGroupBy}).\n * @param categoryId - The tag category to group by (required when `groupBy` is\n * `\"tagCategories\"`).\n * @returns A {@linkcode PluginProgramAreasListResult} with a `groups` array\n * (empty when the program has no spaces).\n *\n * @examplePrompt Break down the area by storey\n * @examplePrompt Show the area rollup per department\n * @examplePrompt Group the built-up area by building\n *\n * # Example\n * ```ts\n * const { groups } = await snaptrude.program.areas.list(\"storeys\")\n * for (const g of groups) console.log(g.name, g.builtUp, g.count)\n * ```\n */\n public abstract list(\n groupBy: PluginProgramAreaGroupBy,\n categoryId?: string,\n ): PluginApiReturn<PluginProgramAreasListResult>\n\n /**\n * List the spaces that make up one area group.\n *\n * Drills into a single bucket returned by {@linkcode\n * PluginProgramAreasApi.list} and returns its member spaces with their per-space\n * area figures.\n *\n * @param groupBy - The same facet used to produce the group (a {@linkcode\n * PluginProgramAreaGroupBy}).\n * @param groupId - The id of the group to expand.\n * @param categoryId - The tag category context (required when `groupBy` is\n * `\"tagCategories\"`).\n * @returns A {@linkcode PluginProgramAreasListMembersResult} with a `members`\n * array (empty when the group is missing or empty).\n *\n * @examplePrompt List the spaces on this storey with their areas\n * @examplePrompt What rooms are in the Bedrooms department bucket?\n * @examplePrompt Break the storey area down into individual spaces\n *\n * # Example\n * ```ts\n * const { members } = await snaptrude.program.areas.listMembers(\"storeys\", \"st_2\")\n * for (const m of members) console.log(m.label, m.carpet)\n * ```\n */\n public abstract listMembers(\n groupBy: PluginProgramAreaGroupBy,\n groupId: string,\n categoryId?: string,\n ): PluginApiReturn<PluginProgramAreasListMembersResult>\n\n /**\n * Update the program's FAR settings.\n *\n * A **sparse** update of the program-level FAR inputs — target FAR, the site\n * area, and the allowed deviation. This is a **non-undoable settings write**\n * (persisted with the project). `achievedFar` recomputes from these.\n *\n * @param options - Any of `targetFar`, `siteArea`, `deviation`; omitted fields\n * are left unchanged.\n * @returns The recomputed {@linkcode PluginProgramAreaSummary}.\n * @throws If a value is out of range.\n *\n * @examplePrompt Set the target FAR to 2.5\n * @examplePrompt Override the site area to 5000\n * @examplePrompt Allow a 10 percent FAR deviation\n *\n * # Example\n * ```ts\n * const s = await snaptrude.program.areas.update({ targetFar: 2.5 })\n * console.log(s.achievedFar, s.targetFar)\n * ```\n */\n public abstract update(\n options?: { targetFar?: number; siteArea?: number; deviation?: number },\n ): PluginApiReturn<PluginProgramAreasUpdateResult>\n}\n\n/**\n * The whole-program area / FAR summary. All area figures are in `areaUnit`;\n * ratios (`achievedFar`, `targetFar`, `deviation`) are unitless.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `count` | `number` | Number of spaces in the program (a count, not an area) |\n * | `hiddenCount` | `number` | Number of those spaces that are currently hidden |\n * | `carpet` | `number` | Total carpet area in `areaUnit` |\n * | `builtUp` | `number` | Total built-up area in `areaUnit` |\n * | `excluded` | `number` | Total excluded area in `areaUnit` |\n * | `farBuiltUp` | `number` | Built-up area that counts toward FAR, in `areaUnit` |\n * | `siteArea` | `number` | Site/plot area in `areaUnit` |\n * | `achievedFar` | `number \\| null` | Derived FAR (`farBuiltUp / siteArea`); `null` when site area or target FAR is unset |\n * | `targetFar` | `number` | The target FAR goal (set via `update`) |\n * | `deviation` | `number` | Allowed FAR deviation, as a percentage |\n * | `areaUnit` | `\"ft2\" \\| \"m2\"` | The unit every area figure above is reported in |\n */\nexport const PluginProgramAreaSummary = z.object({\n count: z.number().int(),\n hiddenCount: z.number().int(),\n carpet: z.number(),\n builtUp: z.number(),\n excluded: z.number(),\n farBuiltUp: z.number(),\n siteArea: z.number(),\n achievedFar: z.number().nullable(),\n targetFar: z.number(),\n deviation: z.number(),\n areaUnit: PluginAreaUnit,\n})\nexport type PluginProgramAreaSummary = z.infer<typeof PluginProgramAreaSummary>\n\n/**\n * One bucket of the area rollup. Carpet / built-up / excluded figures are in the\n * program's area unit (see {@linkcode PluginProgramAreaSummary.areaUnit});\n * `targetArea` is in `targetUnit`.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `groupId` | `string` | Stable id of the group (e.g. storey id, department id) |\n * | `name` | `string` | Display name of the group |\n * | `color` | `string` | CSS hex color string for the group |\n * | `carpet` | `number` | Carpet area for this group |\n * | `builtUp` | `number` | Built-up area for this group |\n * | `excluded` | `number` | Excluded area for this group |\n * | `count` | `number` | Number of spaces in this group |\n * | `targetArea` | `number` | Target area for this group, in `targetUnit` |\n * | `targetUnit` | `\"ft2\" \\| \"m2\"` | The unit `targetArea` is reported in |\n */\nexport const PluginProgramAreaGroup = z.object({\n groupId: z.string(),\n name: z.string(),\n color: z.string(),\n carpet: z.number(),\n builtUp: z.number(),\n excluded: z.number(),\n count: z.number().int(),\n targetArea: z.number(),\n targetUnit: PluginAreaUnit,\n})\nexport type PluginProgramAreaGroup = z.infer<typeof PluginProgramAreaGroup>\n\n/**\n * A single space within an area group. Area figures are in the program's area\n * unit (see {@linkcode PluginProgramAreaSummary.areaUnit}).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `ComponentHandle` | `Component.id` of the space (never a mesh handle) |\n * | `label` | `string` | Display label of the space |\n * | `carpet` | `number` | Carpet area of the space |\n * | `builtUp` | `number` | Built-up area of the space |\n * | `excluded` | `number` | Excluded area of the space |\n * | `isVisible` | `boolean` | Whether the space is currently visible |\n */\nexport const PluginProgramAreaMember = z.object({\n id: ComponentHandle,\n label: z.string(),\n carpet: z.number(),\n builtUp: z.number(),\n excluded: z.number(),\n isVisible: z.boolean(),\n})\nexport type PluginProgramAreaMember = z.infer<typeof PluginProgramAreaMember>\n\n/** The facet to group the area rollup by. */\nexport const PluginProgramAreaGroupBy = z.enum([\n \"labels\",\n \"storeys\",\n \"buildings\",\n \"departments\",\n \"tagCategories\",\n])\nexport type PluginProgramAreaGroupBy = z.infer<typeof PluginProgramAreaGroupBy>\n\n/** Result of {@linkcode PluginProgramAreasApi.get} — the program area summary. */\nexport const PluginProgramAreasGetResult = PluginProgramAreaSummary\nexport type PluginProgramAreasGetResult = z.infer<\n typeof PluginProgramAreasGetResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramAreasApi.list}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `groupBy` | {@linkcode PluginProgramAreaGroupBy} | The facet to group by |\n * | `categoryId` | `string \\| undefined` | Tag category to group by; required when `groupBy` is `\"tagCategories\"` |\n */\nexport const PluginProgramAreasListArgs = z\n .object({\n groupBy: PluginProgramAreaGroupBy,\n categoryId: z.string().optional(),\n })\n .refine((v) => v.groupBy !== \"tagCategories\" || v.categoryId != null, {\n message: 'categoryId is required when groupBy is \"tagCategories\"',\n })\nexport type PluginProgramAreasListArgs = z.infer<\n typeof PluginProgramAreasListArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramAreasApi.list}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `groups` | {@linkcode PluginProgramAreaGroup}`[]` | The area buckets (empty when the program has no spaces) |\n */\nexport const PluginProgramAreasListResult = z.object({\n groups: z.array(PluginProgramAreaGroup),\n})\nexport type PluginProgramAreasListResult = z.infer<\n typeof PluginProgramAreasListResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramAreasApi.listMembers}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `groupBy` | {@linkcode PluginProgramAreaGroupBy} | The facet the group came from |\n * | `groupId` | `string` | The id of the group to expand |\n * | `categoryId` | `string \\| undefined` | Tag category context; required when `groupBy` is `\"tagCategories\"` |\n */\nexport const PluginProgramAreasListMembersArgs = z\n .object({\n groupBy: PluginProgramAreaGroupBy,\n groupId: z.string(),\n categoryId: z.string().optional(),\n })\n .refine((v) => v.groupBy !== \"tagCategories\" || v.categoryId != null, {\n message: 'categoryId is required when groupBy is \"tagCategories\"',\n })\nexport type PluginProgramAreasListMembersArgs = z.infer<\n typeof PluginProgramAreasListMembersArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramAreasApi.listMembers}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `members` | {@linkcode PluginProgramAreaMember}`[]` | The group's member spaces (empty when missing or empty) |\n */\nexport const PluginProgramAreasListMembersResult = z.object({\n members: z.array(PluginProgramAreaMember),\n})\nexport type PluginProgramAreasListMembersResult = z.infer<\n typeof PluginProgramAreasListMembersResult\n>\n\n/**\n * Arguments for {@linkcode PluginProgramAreasApi.update}. Sparse — only the\n * provided fields are changed.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `targetFar` | `number \\| undefined` | New target FAR (≥ 0) |\n * | `siteArea` | `number \\| undefined` | Site-area override (> 0), in the program's area unit |\n * | `deviation` | `number \\| undefined` | Allowed FAR deviation percentage (0–100) |\n */\nexport const PluginProgramAreasUpdateArgs = z.object({\n targetFar: z.number().min(0).optional(),\n siteArea: z.number().positive().optional(),\n deviation: z.number().min(0).max(100).optional(),\n})\nexport type PluginProgramAreasUpdateArgs = z.infer<\n typeof PluginProgramAreasUpdateArgs\n>\n\n/**\n * Result of {@linkcode PluginProgramAreasApi.update} — the recomputed program\n * area summary.\n */\nexport const PluginProgramAreasUpdateResult = PluginProgramAreaSummary\nexport type PluginProgramAreasUpdateResult = z.infer<\n typeof PluginProgramAreasUpdateResult\n>\n","import { PluginProgramDepartmentsApi } from \"./departments\"\nimport { PluginProgramAdjacencyApi } from \"./adjacency\"\nimport { PluginProgramLayoutApi } from \"./layout\"\nimport { PluginProgramMetricsApi } from \"./metrics\"\nimport { PluginProgramSpreadsheetApi } from \"./spreadsheet\"\nimport { PluginProgramSiteApi } from \"./site\"\nimport { PluginProgramCoresApi } from \"./cores\"\nimport { PluginProgramClassificationApi } from \"./classification\"\nimport { PluginProgramAreasApi } from \"./areas\"\n\n/**\n * Program-mode planning APIs.\n *\n * The program is the space-planning layer: department groupings with area targets,\n * the metrics that track allocated area against those targets, and the reports\n * that render program/takeoff data to spreadsheet sheets. Reads describe the\n * *plan* (intent + targets); the geometry that realizes the plan is authored\n * through the geometry namespaces.\n *\n * - {@linkcode PluginProgramApi.departments} — Read & edit program departments (groupings + targets)\n * - {@linkcode PluginProgramApi.adjacency} — Read & compute the department/space adjacency matrix\n * - {@linkcode PluginProgramApi.layout} — Arrange/pack spaces in the envelope (authored ahead)\n * - {@linkcode PluginProgramApi.metrics} — Read the area-program summary\n * - {@linkcode PluginProgramApi.areas} — FAR / built-up-area rollup and groupings\n * - {@linkcode PluginProgramApi.spreadsheet} — Render program data to sheets and read it back\n * - {@linkcode PluginProgramApi.site} — Read the site/plot planning context\n * - {@linkcode PluginProgramApi.cores} — Read & trigger vertical-circulation cores\n * - {@linkcode PluginProgramApi.classification} — Classification catalog + display tags\n *\n * Sub-namespaces typed as optional (`?`) are **authored ahead of the host** —\n * declared so plugins and codegen can see the shape, but not required of host\n * implementations and kept out of the discovery manifest until the host lands\n * them (at which point they are promoted to required `abstract` members).\n *\n * Accessed via `snaptrude.program`.\n */\nexport abstract class PluginProgramApi {\n /** Program departments — groupings, area targets, and space assignment. See {@linkcode PluginProgramDepartmentsApi}. */\n public abstract departments: PluginProgramDepartmentsApi\n /** Adjacency matrix — read & compute proximity relationships. See {@linkcode PluginProgramAdjacencyApi}. */\n public abstract adjacency: PluginProgramAdjacencyApi\n /**\n * Arrange/pack spaces in the envelope. See {@linkcode PluginProgramLayoutApi}.\n * _(authored ahead — optional until the host lands it next increment.)_\n */\n public layout?: PluginProgramLayoutApi\n /** Area-program summary — targets vs allocated area. See {@linkcode PluginProgramMetricsApi}. */\n public abstract metrics: PluginProgramMetricsApi\n /** FAR / built-up-area rollup and groupings. See {@linkcode PluginProgramAreasApi}. */\n public abstract areas: PluginProgramAreasApi\n /** Spreadsheet reports — render tables to sheets, export, list, read back. See {@linkcode PluginProgramSpreadsheetApi}. */\n public abstract spreadsheet: PluginProgramSpreadsheetApi\n /** Site/plot planning context — total area, parcel footprints, geo rings. See {@linkcode PluginProgramSiteApi}. */\n public abstract site: PluginProgramSiteApi\n /** Vertical-circulation cores — read & predicate (live); generation trigger is optional. See {@linkcode PluginProgramCoresApi}. */\n public abstract cores: PluginProgramCoresApi\n /** Classification catalog (space/area/mass types) + display tags. See {@linkcode PluginProgramClassificationApi}. */\n public abstract classification: PluginProgramClassificationApi\n\n constructor() {}\n}\n\nexport * from \"./departments\"\nexport * from \"./adjacency\"\nexport * from \"./layout\"\nexport * from \"./metrics\"\nexport * from \"./spreadsheet\"\nexport * from \"./site\"\nexport * from \"./cores\"\nexport * from \"./classification\"\nexport * from \"./areas\"\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Presentation views — read the saved 2D/3D views used to prepare presentations.\n *\n * A **view** is a saved camera/plan: a sheet-ready 2D plan or a saved 3D view.\n * A plugin can list and read views, capture them to images, activate one (move\n * the camera to it), and save the current camera as a new view.\n *\n * `list`/`get`/`getActive`/`capture` are reads; `setActive`/`create` are writes\n * (a view is a camera bookmark — not geometry). Members typed optional (`?`) are\n * authored ahead of the host: declared for plugins/codegen but not yet on the\n * live discovery surface until the host lands them.\n *\n * Accessed via `snaptrude.presentation.views`.\n */\nexport abstract class PluginPresentationViewsApi {\n constructor() {}\n\n /**\n * List the saved views in the active project.\n *\n * @returns A {@linkcode PluginPresentationViewsListResult} with a `views` array\n * of 2D and 3D views (empty when the project has none).\n *\n * @examplePrompt List all the saved views\n * @examplePrompt What 2D and 3D views are in this project?\n * @examplePrompt Which view is currently active?\n * @examplePrompt Get the names of every presentation view\n * @examplePrompt Show me the 3D views I can put on a sheet\n *\n * # Example\n * ```ts\n * const { views } = await snaptrude.presentation.views.list()\n * const active = views.find((v) => v.isActive)\n * const plans = views.filter((v) => v.type === \"2d\")\n * ```\n */\n public abstract list(): PluginApiReturn<PluginPresentationViewsListResult>\n\n /**\n * Get a single saved view by id.\n *\n * @param viewId - The id of the view to read.\n * @returns The matching {@linkcode PluginPresentationView}, or `null` if no view\n * has that id.\n *\n * @examplePrompt Get the view with id view_12345\n * @examplePrompt Find the saved view called Ground Floor Plan\n * @examplePrompt Look up a presentation view by its id\n *\n * # Example\n * ```ts\n * const view = await snaptrude.presentation.views.get(\"view_123\")\n * ```\n */\n public abstract get(\n viewId: string,\n ): PluginApiReturn<PluginPresentationViewsGetResult>\n\n /**\n * Get the currently active view.\n *\n * @returns The active {@linkcode PluginPresentationView}, or `null` if none is\n * active.\n *\n * @examplePrompt Which view is active right now?\n * @examplePrompt Get the current view\n * @examplePrompt What view am I looking at?\n *\n * # Example\n * ```ts\n * const active = await snaptrude.presentation.views.getActive()\n * ```\n */\n public abstract getActive(): PluginApiReturn<PluginPresentationViewsGetResult>\n\n /**\n * Capture a screenshot of a view as a base64 image.\n *\n * Captures the **current** viewport by default; pass `viewId` to capture a\n * specific saved view (which briefly applies that view to the scene). Use\n * `format`/`resolution` to control the output.\n *\n * @param options - All optional: `viewId` (capture this saved view; omit for the\n * current viewport), `format` (default `\"png\"`), `resolution` (e.g. `\"1280x720\"`).\n * @returns A {@linkcode PluginPresentationViewsCaptureResult} with the base64\n * `image` data URL.\n * @throws If a given `viewId` does not exist.\n *\n * @examplePrompt Take a screenshot of the current view\n * @examplePrompt Capture this view as a PNG\n * @examplePrompt Render the Site Plan view to an image\n * @examplePrompt Export a high-res image of what I'm looking at\n *\n * # Example\n * ```ts\n * const { image } = await snaptrude.presentation.views.capture({ format: \"png\" })\n * ```\n */\n public abstract capture(options?: {\n viewId?: string\n format?: \"png\" | \"jpeg\"\n resolution?: string\n }): PluginApiReturn<PluginPresentationViewsCaptureResult>\n\n /**\n * Activate a saved view — move the camera to it and restore its scene state.\n *\n * Applies the view's camera, visibility, and storey state to the live scene.\n * Paired with {@linkcode PluginPresentationViewsApi.getActive}.\n *\n * @param viewId - The id of the view to activate.\n * @returns The id of the now-active view.\n * @throws If no view has the given id.\n *\n * @examplePrompt Switch to the Ground Floor plan view\n * @examplePrompt Make the 3D view active\n * @examplePrompt Go to the view named Entrance\n * @examplePrompt Load the site plan view\n *\n * # Example\n * ```ts\n * await snaptrude.presentation.views.setActive(\"view_123\")\n * ```\n */\n public abstract setActive(\n viewId: string,\n ): PluginApiReturn<PluginPresentationViewsSetActiveResult>\n\n /**\n * Save the current camera/scene state as a new named view.\n *\n * Creates a camera bookmark (not geometry) from where the camera is now.\n *\n * @param name - Name for the new view (a default is used when omitted).\n * @param options - Optional `kind`: what kind of view to save (default `\"view\"`).\n * @returns The newly created {@linkcode PluginPresentationView}.\n * @throws If the view could not be saved.\n *\n * @examplePrompt Save the current view as Lobby Perspective\n * @examplePrompt Create a new saved view from where I'm looking\n * @examplePrompt Bookmark this camera angle\n * @examplePrompt Save the current 2D plan as a view\n *\n * # Example\n * ```ts\n * const view = await snaptrude.presentation.views.create(\"Lobby\")\n * ```\n */\n public abstract create(\n name?: string,\n options?: { kind?: \"view\" | \"sitePlan\" },\n ): PluginApiReturn<PluginPresentationViewsCreateResult>\n}\n\n/**\n * The kind of a saved view: a 2D plan view or a 3D view.\n */\nexport const PluginPresentationViewType = z.enum([\"2d\", \"3d\"])\nexport type PluginPresentationViewType = z.infer<\n typeof PluginPresentationViewType\n>\n\n/**\n * A saved presentation view.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Unique view id |\n * | `name` | `string` | Display name |\n * | `type` | `\"2d\" \\| \"3d\"` | Whether this is a 2D plan view or a 3D view |\n * | `isActive` | `boolean` | Whether this view is the currently active view |\n */\nexport const PluginPresentationView = z.object({\n id: z.string(),\n name: z.string(),\n type: PluginPresentationViewType,\n isActive: z.boolean(),\n})\nexport type PluginPresentationView = z.infer<typeof PluginPresentationView>\n\n/**\n * Result of {@linkcode PluginPresentationViewsApi.list}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `views` | {@linkcode PluginPresentationView}`[]` | All saved views in the project |\n */\nexport const PluginPresentationViewsListResult = z.object({\n views: z.array(PluginPresentationView),\n})\nexport type PluginPresentationViewsListResult = z.infer<\n typeof PluginPresentationViewsListResult\n>\n\n/**\n * Arguments for {@linkcode PluginPresentationViewsApi.get}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | The id of the view to read |\n */\nexport const PluginPresentationViewsGetArgs = z.object({\n id: z.string(),\n})\nexport type PluginPresentationViewsGetArgs = z.infer<\n typeof PluginPresentationViewsGetArgs\n>\n\n/**\n * Result of {@linkcode PluginPresentationViewsApi.get} and\n * {@linkcode PluginPresentationViewsApi.getActive} — the view, or `null` when\n * there is no match / no active view.\n */\nexport const PluginPresentationViewsGetResult =\n PluginPresentationView.nullable()\nexport type PluginPresentationViewsGetResult = z.infer<\n typeof PluginPresentationViewsGetResult\n>\n\n/** Image format for {@linkcode PluginPresentationViewsApi.capture}. */\nexport const PluginPresentationImageFormat = z.enum([\"png\", \"jpeg\"])\nexport type PluginPresentationImageFormat = z.infer<\n typeof PluginPresentationImageFormat\n>\n\n/**\n * Arguments for {@linkcode PluginPresentationViewsApi.capture}. All optional.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `viewId` | `string \\| undefined` | Capture this saved view; omit to capture the current viewport |\n * | `format` | `\"png\" \\| \"jpeg\" \\| undefined` | Output image format (default `\"png\"`) |\n * | `resolution` | `string \\| undefined` | Optional resolution hint (e.g. `\"1280x720\"`) |\n */\nexport const PluginPresentationViewsCaptureArgs = z.object({\n viewId: z.string().optional(),\n format: PluginPresentationImageFormat.optional(),\n resolution: z.string().optional(),\n})\nexport type PluginPresentationViewsCaptureArgs = z.infer<\n typeof PluginPresentationViewsCaptureArgs\n>\n\n/**\n * Result of {@linkcode PluginPresentationViewsApi.capture}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `image` | `string` | The captured image as a base64 data URL |\n */\nexport const PluginPresentationViewsCaptureResult = z.object({\n image: z.string(),\n})\nexport type PluginPresentationViewsCaptureResult = z.infer<\n typeof PluginPresentationViewsCaptureResult\n>\n\n/**\n * Arguments for {@linkcode PluginPresentationViewsApi.setActive}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | The id of the view to activate |\n */\nexport const PluginPresentationViewsSetActiveArgs = z.object({\n id: z.string(),\n})\nexport type PluginPresentationViewsSetActiveArgs = z.infer<\n typeof PluginPresentationViewsSetActiveArgs\n>\n\n/** Result of {@linkcode PluginPresentationViewsApi.setActive} — the active view's id. */\nexport const PluginPresentationViewsSetActiveResult = z.object({\n id: z.string(),\n})\nexport type PluginPresentationViewsSetActiveResult = z.infer<\n typeof PluginPresentationViewsSetActiveResult\n>\n\n/**\n * Arguments for {@linkcode PluginPresentationViewsApi.create}. All optional.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `name` | `string \\| undefined` | Name for the new view (a default is used when omitted) |\n * | `kind` | `\"view\" \\| \"sitePlan\" \\| undefined` | What kind of view to save (default `\"view\"`). `\"plan\"` is not offered — the host cannot create a plan view without a `planId` this API does not carry. |\n */\nexport const PluginPresentationViewsCreateArgs = z.object({\n name: z.string().optional(),\n kind: z.enum([\"view\", \"sitePlan\"]).optional(),\n})\nexport type PluginPresentationViewsCreateArgs = z.infer<\n typeof PluginPresentationViewsCreateArgs\n>\n\n/** Result of {@linkcode PluginPresentationViewsApi.create} — the saved view. */\nexport const PluginPresentationViewsCreateResult = PluginPresentationView\nexport type PluginPresentationViewsCreateResult = z.infer<\n typeof PluginPresentationViewsCreateResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Presentation sheets — the layout sheets a presentation is assembled on.\n *\n * A **sheet** is a page in Present mode that views and diagrams are placed onto.\n * These methods require **Present mode to be open** (the documentation editor) —\n * reads return `[]`/`null` and writes throw when it is not.\n *\n * `list`/`get` are reads; `create` adds a sheet and `place` drops a saved view\n * onto a sheet (returning the id of the created canvas shape).\n *\n * Accessed via `snaptrude.presentation.sheets`.\n */\nexport abstract class PluginPresentationSheetsApi {\n constructor() {}\n\n /**\n * List the layout sheets in the presentation.\n *\n * @returns A {@linkcode PluginPresentationSheetsListResult} with a `sheets`\n * array (empty when Present mode is closed or there are no sheets).\n *\n * @examplePrompt List all the sheets\n * @examplePrompt How many layout sheets are there?\n * @examplePrompt Show me the presentation sheets\n * @examplePrompt What sheets can I place views on?\n *\n * # Example\n * ```ts\n * const { sheets } = await snaptrude.presentation.sheets.list()\n * ```\n */\n public abstract list(): PluginApiReturn<PluginPresentationSheetsListResult>\n\n /**\n * Get a single sheet by id.\n *\n * @param sheetId - The id of the sheet to read.\n * @returns The matching {@linkcode PluginPresentationSheet}, or `null`.\n *\n * @examplePrompt Get the sheet with id sheet_1\n * @examplePrompt Find the sheet called Cover\n * @examplePrompt Look up a layout sheet by id\n *\n * # Example\n * ```ts\n * const sheet = await snaptrude.presentation.sheets.get(\"sheet_1\")\n * ```\n */\n public abstract get(\n sheetId: string,\n ): PluginApiReturn<PluginPresentationSheetsGetResult>\n\n /**\n * Create a new layout sheet.\n *\n * Requires Present mode to be open.\n *\n * @param name - Display name for the new sheet (optional).\n * @returns The newly created {@linkcode PluginPresentationSheet}.\n * @throws If Present mode is not open.\n *\n * @examplePrompt Create a new sheet called Cover\n * @examplePrompt Add a layout sheet\n * @examplePrompt Make a new presentation sheet named Floor Plans\n *\n * # Example\n * ```ts\n * const sheet = await snaptrude.presentation.sheets.create(\"Cover\")\n * ```\n */\n public abstract create(\n name?: string,\n ): PluginApiReturn<PluginPresentationSheet>\n\n /**\n * Place a saved view onto a sheet.\n *\n * Drops the given view onto the sheet at an optional position and returns the\n * id of the created canvas shape. Requires Present mode to be open.\n *\n * @param sheetId - The id of the sheet to place onto.\n * @param viewId - The id of the saved view to place.\n * @param options - Optional `position` ({@linkcode PluginSheetPosition}) —\n * where to place it (a default is used when omitted).\n * @returns A {@linkcode PluginPresentationSheetsPlaceResult} with the created\n * `shapeId`.\n * @throws If Present mode is not open, or the sheet/view id is invalid.\n *\n * @examplePrompt Place the floor plan on Sheet 1\n * @examplePrompt Add this 3D view to the cover sheet\n * @examplePrompt Drop the site plan onto the layout sheet at 100, 200\n * @examplePrompt Put the Ground Floor view on sheet_1\n *\n * # Example\n * ```ts\n * const { shapeId } = await snaptrude.presentation.sheets.place(\"sheet_1\", \"view_123\")\n * ```\n */\n public abstract place(\n sheetId: string,\n viewId: string,\n options?: { position?: PluginSheetPosition },\n ): PluginApiReturn<PluginPresentationSheetsPlaceResult>\n}\n\n/**\n * A layout sheet in the presentation.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `id` | `string` | Unique sheet id |\n * | `name` | `string` | Display name |\n */\nexport const PluginPresentationSheet = z.object({\n id: z.string(),\n name: z.string(),\n})\nexport type PluginPresentationSheet = z.infer<typeof PluginPresentationSheet>\n\n/**\n * A position on a sheet/canvas (sheet coordinates).\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `x` | `number` | X coordinate |\n * | `y` | `number` | Y coordinate |\n */\nexport const PluginSheetPosition = z.object({\n x: z.number(),\n y: z.number(),\n})\nexport type PluginSheetPosition = z.infer<typeof PluginSheetPosition>\n\n/** Result of {@linkcode PluginPresentationSheetsApi.list}. */\nexport const PluginPresentationSheetsListResult = z.object({\n sheets: z.array(PluginPresentationSheet),\n})\nexport type PluginPresentationSheetsListResult = z.infer<\n typeof PluginPresentationSheetsListResult\n>\n\n/** Arguments for {@linkcode PluginPresentationSheetsApi.get}. */\nexport const PluginPresentationSheetsGetArgs = z.object({\n id: z.string(),\n})\nexport type PluginPresentationSheetsGetArgs = z.infer<\n typeof PluginPresentationSheetsGetArgs\n>\n\n/** Result of {@linkcode PluginPresentationSheetsApi.get} — the sheet, or `null`. */\nexport const PluginPresentationSheetsGetResult =\n PluginPresentationSheet.nullable()\nexport type PluginPresentationSheetsGetResult = z.infer<\n typeof PluginPresentationSheetsGetResult\n>\n\n/** Arguments for {@linkcode PluginPresentationSheetsApi.create}. */\nexport const PluginPresentationSheetsCreateArgs = z.object({\n name: z.string().optional(),\n})\nexport type PluginPresentationSheetsCreateArgs = z.infer<\n typeof PluginPresentationSheetsCreateArgs\n>\n\n/**\n * Arguments for {@linkcode PluginPresentationSheetsApi.place}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetId` | `string` | The sheet to place onto |\n * | `viewId` | `string` | The saved view to place |\n * | `position` | {@linkcode PluginSheetPosition}` \\| undefined` | Where to place it (a default is used when omitted) |\n */\nexport const PluginPresentationSheetsPlaceArgs = z.object({\n sheetId: z.string(),\n viewId: z.string(),\n position: PluginSheetPosition.optional(),\n})\nexport type PluginPresentationSheetsPlaceArgs = z.infer<\n typeof PluginPresentationSheetsPlaceArgs\n>\n\n/**\n * Result of {@linkcode PluginPresentationSheetsApi.place}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `shapeId` | `string` | Id of the created canvas shape |\n */\nexport const PluginPresentationSheetsPlaceResult = z.object({\n shapeId: z.string(),\n})\nexport type PluginPresentationSheetsPlaceResult = z.infer<\n typeof PluginPresentationSheetsPlaceResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Presentation diagrams — place diagram images onto sheets.\n *\n * {@linkcode PluginPresentationDiagramsApi.place} drops diagram images (by\n * URL) onto a sheet and returns the created canvas shape ids (requires Present\n * mode to be open). Adjacency data itself is read and computed via\n * `program.adjacency` (see {@linkcode PluginProgramAdjacencyApi}).\n *\n * A future one-step spec-based `place` — which would render a diagram spec\n * and place it in a single call — awaits a public generator from the\n * documentation engine; until that generator exists, `place` takes ready\n * image `urls` (we do not ship a spec-based `place` that would only throw).\n *\n * Accessed via `snaptrude.presentation.diagrams`.\n */\nexport abstract class PluginPresentationDiagramsApi {\n constructor() {}\n\n /**\n * Place diagram images onto a sheet.\n *\n * Drops the given diagram image URLs onto a sheet and returns the ids of the\n * created canvas shapes. Requires Present mode to be open.\n *\n * @param sheetId - The sheet to place onto.\n * @param urls - Diagram image URLs to place.\n * @param options - Optional `position` (`{ x, y }`, relative to the sheet)\n * for the placed images.\n * @returns A {@linkcode PluginPresentationDiagramsPlaceResult} with the created\n * `shapeIds`.\n * @throws If Present mode is not open or the sheet id is invalid.\n *\n * @examplePrompt Place the adjacency diagram on Sheet 1\n * @examplePrompt Add the program diagram to the cover sheet\n * @examplePrompt Drop these diagram images onto the layout\n *\n * # Example\n * ```ts\n * await snaptrude.presentation.diagrams.place(\"sheet_1\", [\n * \"https://example.com/program-diagram.png\",\n * ])\n * ```\n */\n public abstract place(\n sheetId: string,\n urls: string[],\n options?: { position?: { x: number; y: number } },\n ): PluginApiReturn<PluginPresentationDiagramsPlaceResult>\n}\n\n/**\n * Arguments for {@linkcode PluginPresentationDiagramsApi.place}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `sheetId` | `string` | The sheet to place onto |\n * | `urls` | `string[]` | Diagram image URLs |\n * | `position` | `{ x: number; y: number } \\| undefined` | Where to place them |\n */\nexport const PluginPresentationDiagramsPlaceArgs = z.object({\n sheetId: z.string(),\n urls: z.array(z.string()),\n position: z.object({ x: z.number(), y: z.number() }).optional(),\n})\nexport type PluginPresentationDiagramsPlaceArgs = z.infer<\n typeof PluginPresentationDiagramsPlaceArgs\n>\n\n/**\n * Result of {@linkcode PluginPresentationDiagramsApi.place}.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `shapeIds` | `string[]` | Ids of the created canvas shapes |\n */\nexport const PluginPresentationDiagramsPlaceResult = z.object({\n shapeIds: z.array(z.string()),\n})\nexport type PluginPresentationDiagramsPlaceResult = z.infer<\n typeof PluginPresentationDiagramsPlaceResult\n>\n","import * as z from \"zod\"\nimport { PluginApiReturn } from \"../../types\"\n\n/**\n * Presentation import — bring external reference assets onto the Present canvas.\n *\n * `import.image` places a reference image and `import.pdf` places a PDF (each\n * page vectorized to SVG) onto the current Present sheet, returning the created\n * canvas shape ids. Requires Present mode to be open.\n *\n * The host engine takes a browser `File`, which a plugin worker cannot supply,\n * so these accept a `url`/`dataUrl` that the host adapts into a `File`.\n *\n * Accessed via `snaptrude.presentation.import`.\n */\nexport abstract class PluginPresentationImportApi {\n constructor() {}\n\n /**\n * Import a reference image onto the current Present sheet.\n *\n * @param source - The asset to import: exactly one of `url` or `dataUrl`.\n * @param options - Optional `position` — where to place the image on the\n * sheet.\n * @returns A {@linkcode PluginPresentationImportResult} with the created\n * `shapeIds`.\n * @throws If Present mode is not open or the source cannot be loaded.\n *\n * @examplePrompt Import this reference image onto the present canvas\n * @examplePrompt Add a JPG to my presentation board\n * @examplePrompt Drop this site photo onto the current sheet\n * @examplePrompt Bring an inspiration image into Present mode\n *\n * # Example\n * ```ts\n * const { shapeIds } = await snaptrude.presentation.import.image(\n * { url: \"https://example.com/ref.png\" },\n * { position: { x: 200, y: 150 } },\n * )\n * ```\n */\n public abstract image(\n source: { url?: string; dataUrl?: string },\n options?: { position?: { x: number; y: number } },\n ): PluginApiReturn<PluginPresentationImportResult>\n\n /**\n * Import a PDF onto the current Present sheet (one shape per page).\n *\n * Each page is converted to vector SVG and placed as a canvas shape.\n *\n * @param source - The asset to import: exactly one of `url` or `dataUrl`.\n * @param options - Optional `position` — where to place the pages on the\n * sheet.\n * @returns A {@linkcode PluginPresentationImportResult} with one `shapeId` per\n * page.\n * @throws If Present mode is not open or the source cannot be loaded.\n *\n * @examplePrompt Import this PDF onto the present canvas\n * @examplePrompt Add a multi-page PDF reference to my board\n * @examplePrompt Bring a PDF floor plan into Present mode as vectors\n * @examplePrompt Place each page of this PDF on the sheet\n *\n * # Example\n * ```ts\n * const { shapeIds } = await snaptrude.presentation.import.pdf({\n * url: \"https://example.com/plans.pdf\",\n * })\n * ```\n */\n public abstract pdf(\n source: { url?: string; dataUrl?: string },\n options?: { position?: { x: number; y: number } },\n ): PluginApiReturn<PluginPresentationImportResult>\n}\n\n/**\n * Arguments for {@linkcode PluginPresentationImportApi.image} /\n * {@linkcode PluginPresentationImportApi.pdf}. Provide exactly one source.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `url` | `string \\| undefined` | URL of the asset to import |\n * | `dataUrl` | `string \\| undefined` | Base64 data URL of the asset |\n * | `position` | `{ x: number; y: number } \\| undefined` | Where to place it on the sheet |\n */\nexport const PluginPresentationImportArgs = z\n .object({\n url: z.string().optional(),\n dataUrl: z.string().optional(),\n position: z.object({ x: z.number(), y: z.number() }).optional(),\n })\n .refine((a) => Boolean(a.url) || Boolean(a.dataUrl), {\n message: \"Provide a url or a dataUrl\",\n })\nexport type PluginPresentationImportArgs = z.infer<\n typeof PluginPresentationImportArgs\n>\n\n/**\n * Result of an import.\n *\n * | Property | Type | Description |\n * |---|---|---|\n * | `shapeIds` | `string[]` | Ids of the created canvas shapes (one per page for PDFs) |\n */\nexport const PluginPresentationImportResult = z.object({\n shapeIds: z.array(z.string()),\n})\nexport type PluginPresentationImportResult = z.infer<\n typeof PluginPresentationImportResult\n>\n","import * as z from \"zod\"\nimport type { PluginApiReturn } from \"../../types\"\n\nconst JsonPrimitive = z.union([z.string(), z.number(), z.boolean(), z.null()])\ntype JsonValue =\n | z.infer<typeof JsonPrimitive>\n | JsonValue[]\n | { [key: string]: JsonValue }\nconst JsonValue: z.ZodType<JsonValue> = z.lazy(() =>\n z.union([JsonPrimitive, z.array(JsonValue), z.record(z.string(), JsonValue)]),\n)\n\nexport const PluginAIInspirationOutputKind = z.enum([\n \"source\",\n \"image\",\n \"video\",\n])\nexport type PluginAIInspirationOutputKind = z.infer<\n typeof PluginAIInspirationOutputKind\n>\n\nexport const PluginAIInspirationModelOutput = z.enum([\"image\", \"video\"])\nexport type PluginAIInspirationModelOutput = z.infer<\n typeof PluginAIInspirationModelOutput\n>\n\nexport const PluginAIInspirationShapeKind = z.enum([\"image\", \"view\", \"video\"])\nexport type PluginAIInspirationShapeKind = z.infer<\n typeof PluginAIInspirationShapeKind\n>\n\nexport const PluginAIInspirationVideoMode = z.enum([\n \"animate\",\n \"references\",\n \"keyframes\",\n])\nexport type PluginAIInspirationVideoMode = z.infer<\n typeof PluginAIInspirationVideoMode\n>\n\nexport const PluginAIInspirationVideoMotion = z.enum([\n \"auto\",\n \"slow-dolly\",\n \"subtle-orbit\",\n \"reveal\",\n])\nexport type PluginAIInspirationVideoMotion = z.infer<\n typeof PluginAIInspirationVideoMotion\n>\n\nexport const PluginAIInspirationVideoDuration = z.enum([\"4s\", \"6s\", \"8s\"])\nexport type PluginAIInspirationVideoDuration = z.infer<\n typeof PluginAIInspirationVideoDuration\n>\n\nexport const PluginAIInspirationRegionHint = z.object({\n x: z.number().finite(),\n y: z.number().finite(),\n w: z.number().finite().positive(),\n h: z.number().finite().positive(),\n})\nexport type PluginAIInspirationRegionHint = z.infer<\n typeof PluginAIInspirationRegionHint\n>\n\nexport const PluginAIInspirationPoint = z.object({\n x: z.number().finite(),\n y: z.number().finite(),\n})\nexport type PluginAIInspirationPoint = z.infer<typeof PluginAIInspirationPoint>\n\nexport const PluginAIInspirationTextAnnotation = z.object({\n text: z.string().min(1),\n x: z.number().finite().optional(),\n y: z.number().finite().optional(),\n})\nexport type PluginAIInspirationTextAnnotation = z.infer<\n typeof PluginAIInspirationTextAnnotation\n>\n\nexport const PluginAIInspirationSketchGuidance = z.object({\n visualShapeIds: z.array(z.string()).optional(),\n textAnnotations: z.array(PluginAIInspirationTextAnnotation).optional(),\n})\nexport type PluginAIInspirationSketchGuidance = z.infer<\n typeof PluginAIInspirationSketchGuidance\n>\n\nexport const PluginAIInspirationSiteOptions = z.object({\n includeSatellite: z.boolean().optional(),\n includeStreetView: z.boolean().optional(),\n includeAerial: z.boolean().optional(),\n aerialBearing: z.number().finite().optional(),\n aerialPitch: z.number().finite().optional(),\n selectedDiagramIds: z.array(z.string()).optional(),\n location: z\n .object({\n lat: z.number().finite(),\n lng: z.number().finite(),\n })\n .optional(),\n})\nexport type PluginAIInspirationSiteOptions = z.infer<\n typeof PluginAIInspirationSiteOptions\n>\n\nexport const PluginAIInspirationAppliedPreset = z.object({\n source: z.enum([\"curated\", \"user\"]),\n presetId: z.string().min(1),\n name: z.string().min(1),\n savedPresetKind: z.enum([\"prompt\", \"style\"]).optional(),\n stylePrompt: z.string().optional(),\n modelId: z.string().optional(),\n referenceImages: z\n .array(\n z.object({\n url: z.string().min(1),\n label: z.string().optional(),\n weight: z.number().finite().optional(),\n }),\n )\n .optional(),\n siteDefaults: z\n .object({\n includeSatellite: z.boolean().optional(),\n includeStreetView: z.boolean().optional(),\n includeAerial: z.boolean().optional(),\n })\n .optional(),\n})\nexport type PluginAIInspirationAppliedPreset = z.infer<\n typeof PluginAIInspirationAppliedPreset\n>\n\nexport const PluginAIInspirationVideoOptions = z.object({\n mode: PluginAIInspirationVideoMode.optional(),\n endFrameShapeId: z.string().optional(),\n motion: PluginAIInspirationVideoMotion.optional(),\n duration: PluginAIInspirationVideoDuration.optional(),\n})\nexport type PluginAIInspirationVideoOptions = z.infer<\n typeof PluginAIInspirationVideoOptions\n>\n\nexport const PluginAIInspirationModel = z.object({\n id: z.string(),\n label: z.string(),\n supportsMultiImage: z.boolean(),\n output: PluginAIInspirationModelOutput,\n isDefault: z.boolean().optional(),\n})\nexport type PluginAIInspirationModel = z.infer<typeof PluginAIInspirationModel>\n\nexport const PluginAIInspirationListModelsResult = z.object({\n defaultModelId: z.string(),\n models: z.array(PluginAIInspirationModel),\n})\nexport type PluginAIInspirationListModelsResult = z.infer<\n typeof PluginAIInspirationListModelsResult\n>\n\nexport const PluginAIInspirationShapeRef = z.object({\n shapeId: z.string(),\n assetId: z.string().optional(),\n kind: PluginAIInspirationShapeKind,\n name: z.string().optional(),\n width: z.number().finite().optional(),\n height: z.number().finite().optional(),\n outputType: PluginAIInspirationOutputKind.optional(),\n sourceUrl: z.string().optional(),\n})\nexport type PluginAIInspirationShapeRef = z.infer<\n typeof PluginAIInspirationShapeRef\n>\n\nexport const PluginAIInspirationListSourcesArgs = z.object({\n includeGenerated: z.boolean().optional(),\n includeSourceUrl: z.boolean().optional(),\n})\nexport type PluginAIInspirationListSourcesArgs = z.infer<\n typeof PluginAIInspirationListSourcesArgs\n>\n\nexport const PluginAIInspirationListSourcesResult = z.object({\n sources: z.array(PluginAIInspirationShapeRef),\n})\nexport type PluginAIInspirationListSourcesResult = z.infer<\n typeof PluginAIInspirationListSourcesResult\n>\n\nexport const PluginAIInspirationOutput = z.object({\n outputType: z.enum([\"image\", \"video\"]),\n shapeId: z.string(),\n assetId: z.string(),\n outputUrl: z.string().optional(),\n position: PluginAIInspirationPoint.optional(),\n})\nexport type PluginAIInspirationOutput = z.infer<\n typeof PluginAIInspirationOutput\n>\n\nexport const PluginAIInspirationDebugSummary = z.record(z.string(), JsonValue)\nexport type PluginAIInspirationDebugSummary = z.infer<\n typeof PluginAIInspirationDebugSummary\n>\n\nexport const PluginAIInspirationRunMetadata = z.object({\n geometryFidelity: z.string().optional(),\n debugSummary: PluginAIInspirationDebugSummary.optional(),\n streetViewComposite: z\n .object({\n used: z.boolean(),\n renderMode: z.enum([\"prompt_refs_default\", \"masked_composite_pilot\"]),\n backgroundLabel: z.string().optional(),\n })\n .optional(),\n})\nexport type PluginAIInspirationRunMetadata = z.infer<\n typeof PluginAIInspirationRunMetadata\n>\n\nexport const PluginAIInspirationGenerateArgs = z.object({\n sourceShapeId: z.string().min(1),\n prompt: z.string().min(1).max(8000),\n modelId: z.string().optional(),\n referenceShapeIds: z.array(z.string()).max(12).optional(),\n referenceStrength: z.enum([\"low\", \"medium\", \"high\"]).optional(),\n appliedPreset: PluginAIInspirationAppliedPreset.optional(),\n site: PluginAIInspirationSiteOptions.optional(),\n regionHint: PluginAIInspirationRegionHint.optional(),\n sketchGuidance: PluginAIInspirationSketchGuidance.optional(),\n video: PluginAIInspirationVideoOptions.optional(),\n})\nexport type PluginAIInspirationGenerateArgs = z.infer<\n typeof PluginAIInspirationGenerateArgs\n>\n\nexport const PluginAIInspirationRunResult = z.object({\n outputs: z.array(PluginAIInspirationOutput).min(1),\n metadata: PluginAIInspirationRunMetadata.optional(),\n})\nexport type PluginAIInspirationRunResult = z.infer<\n typeof PluginAIInspirationRunResult\n>\n\nexport const PluginAIInspirationRefineArgs = z.object({\n sourceShapeId: z.string().min(1),\n upscaleFactor: z\n .union([z.literal(1.5), z.literal(2), z.literal(4)])\n .optional(),\n})\nexport type PluginAIInspirationRefineArgs = z.infer<\n typeof PluginAIInspirationRefineArgs\n>\n\n/**\n * Present-mode AI Inspiration APIs.\n *\n * These APIs operate on Present canvas shape IDs and inherit the current user's\n * AI quota. They create outputs on the Present canvas; pure backend generation\n * without canvas output is intentionally out of scope.\n *\n * Accessed via `snaptrude.presentation.aiInspiration`.\n */\nexport abstract class PluginPresentationAIInspirationApi {\n constructor() {}\n\n /**\n * List AI Inspiration models that can be used for generation.\n *\n * @returns The default model ID and available model descriptors.\n *\n * @examplePrompt What AI inspiration models can I use?\n * @examplePrompt List the available image and video models\n * @examplePrompt Which generation model is the default?\n *\n * # Example\n * ```ts\n * const { defaultModelId, models } = await snaptrude.presentation.aiInspiration.listModels()\n * const videoModels = models.filter((m) => m.output === \"video\")\n * console.log(defaultModelId, videoModels.map((m) => m.id))\n * ```\n */\n public abstract listModels(): PluginApiReturn<PluginAIInspirationListModelsResult>\n\n /**\n * List image/view/video sources on the current Present page.\n *\n * @param args - Optional filters. Set `includeGenerated` to include AI outputs.\n * @returns Serializable shape references using Present canvas shape IDs.\n *\n * @examplePrompt List the images I can generate from on this page\n * @examplePrompt What source shapes are on the present canvas?\n * @examplePrompt Show me the reference images available for AI generation\n *\n * # Example\n * ```ts\n * const { sources } = await snaptrude.presentation.aiInspiration.listSources({ includeGenerated: true })\n * for (const s of sources) console.log(s.kind, s.shapeId, s.name)\n * ```\n */\n public abstract listSources(\n args: PluginAIInspirationListSourcesArgs,\n ): PluginApiReturn<PluginAIInspirationListSourcesResult>\n\n /**\n * Generate an image or video from a Present canvas source.\n *\n * @param args - Generation options including source, prompt, model, references, site context,\n * region guidance, sketch guidance, and video options.\n * @returns The created canvas output(s).\n *\n * @examplePrompt Generate an image from this sketch\n * @examplePrompt Render the selected view as a photorealistic image\n * @examplePrompt Make an AI image of a modern facade from this source\n * @examplePrompt Generate a video from this image\n * @examplePrompt Turn this massing into a rendered street view\n *\n * # Example\n * ```ts\n * const { sources } = await snaptrude.presentation.aiInspiration.listSources({})\n * const [source, ...refs] = sources\n * const { outputs } = await snaptrude.presentation.aiInspiration.generate({\n * sourceShapeId: source.shapeId,\n * prompt: \"Photorealistic render of a modern timber facade at dusk\",\n * referenceShapeIds: refs.slice(0, 2).map((r) => r.shapeId),\n * referenceStrength: \"medium\",\n * })\n * for (const out of outputs) console.log(out.outputType, out.shapeId, out.outputUrl)\n * ```\n */\n public abstract generate(\n args: PluginAIInspirationGenerateArgs,\n ): PluginApiReturn<PluginAIInspirationRunResult>\n\n /**\n * Refine/upscale an AI Inspiration source image.\n *\n * @param args - Source shape and optional upscale factor.\n * @returns The refined canvas output(s).\n *\n * @examplePrompt Upscale this AI image\n * @examplePrompt Refine and sharpen the selected render\n * @examplePrompt Make this generated image higher resolution\n *\n * # Example\n * ```ts\n * const { sources } = await snaptrude.presentation.aiInspiration.listSources({ includeGenerated: true })\n * const image = sources.find((s) => s.kind === \"image\")\n * if (image) {\n * const { outputs } = await snaptrude.presentation.aiInspiration.refine({\n * sourceShapeId: image.shapeId,\n * upscaleFactor: 2,\n * })\n * console.log(outputs[0].shapeId)\n * }\n * ```\n */\n public abstract refine(\n args: PluginAIInspirationRefineArgs,\n ): PluginApiReturn<PluginAIInspirationRunResult>\n}\n","import { PluginPresentationViewsApi } from \"./views\"\nimport { PluginPresentationAIInspirationApi } from \"./aiInspiration\"\nimport { PluginPresentationSheetsApi } from \"./sheets\"\nimport { PluginPresentationDiagramsApi } from \"./diagrams\"\nimport { PluginPresentationImportApi } from \"./import\"\n\n/**\n * Presentation APIs — prepare and assemble presentations.\n *\n * Reads describe the artifacts a presentation is built from (saved views, layout\n * sheets); writes assemble them (place views/diagrams on sheets, import\n * references, capture/save views). Present-mode AI Inspiration also lives here.\n *\n * Several members require **Present mode to be open** (the documentation editor):\n * sheets, diagram placement, and import.\n *\n * - {@linkcode PluginPresentationApi.views} — Saved 2D/3D views (list, get, capture, activate, create)\n * - {@linkcode PluginPresentationApi.sheets} — Layout sheets (list, get, create, place views)\n * - {@linkcode PluginPresentationApi.diagrams} — Place program/adjacency/site diagram images on sheets\n * - {@linkcode PluginPresentationApi.import} — Import reference images/PDFs onto the canvas\n * - {@linkcode PluginPresentationApi.aiInspiration} — Present-mode AI image/video generation\n *\n * Accessed via `snaptrude.presentation`.\n */\nexport abstract class PluginPresentationApi {\n /** Saved 2D/3D views. See {@linkcode PluginPresentationViewsApi}. */\n public abstract views: PluginPresentationViewsApi\n /** Layout sheets — list/get/create and place views (Present mode). See {@linkcode PluginPresentationSheetsApi}. */\n public abstract sheets: PluginPresentationSheetsApi\n /** Program/adjacency/site diagrams — place images on sheets. See {@linkcode PluginPresentationDiagramsApi}. */\n public abstract diagrams: PluginPresentationDiagramsApi\n /** Import reference images/PDFs onto the Present canvas. See {@linkcode PluginPresentationImportApi}. */\n public abstract import: PluginPresentationImportApi\n /**\n * Present-mode AI Inspiration image/video generation. See\n * {@linkcode PluginPresentationAIInspirationApi}. _(authored ahead — optional\n * until the host lands; the host implementation today is a stub.)_\n */\n public aiInspiration?: PluginPresentationAIInspirationApi\n\n constructor() {}\n}\n\nexport * from \"./views\"\nexport * from \"./sheets\"\nexport * from \"./diagrams\"\nexport * from \"./import\"\nexport * from \"./aiInspiration\"\n","import { PluginCoreApi } from \"./core\"\nimport { PluginDesignApi } from \"./design\"\nimport { PluginEntityApi } from \"./entity\"\nimport { PluginProgramApi } from \"./program\"\nimport { PluginPresentationApi } from \"./presentation\"\n\n/**\n * Root API surface for Snaptrude plugins.\n *\n * Access all plugin capabilities through the namespaced properties:\n *\n * - {@linkcode PluginApi.core} — Math, geometry kernel, history, units, zoom, project, comments (infrastructure)\n * - {@linkcode PluginApi.design} — Author, query & edit BIM geometry\n * - {@linkcode PluginApi.entity} — CRUD operations on Snaptrude entities (spaces, stories)\n * - {@linkcode PluginApi.program} — Program-mode planning reads (departments, metrics)\n * - {@linkcode PluginApi.presentation} — Presentation preparation (views, AI Inspiration)\n */\nexport abstract class PluginApi {\n /** Core math, geometry, history, and units primitives. See {@linkcode PluginCoreApi}. */\n public abstract core: PluginCoreApi\n /** Author, query & edit BIM geometry. See {@linkcode PluginDesignApi}. */\n public abstract design: PluginDesignApi\n /** CRUD operations on Snaptrude entities. See {@linkcode PluginEntityApi}. */\n public abstract entity: PluginEntityApi\n /** Program-mode planning reads — departments and area metrics. See {@linkcode PluginProgramApi}. */\n public abstract program: PluginProgramApi\n /** Presentation preparation reads — saved views. See {@linkcode PluginPresentationApi}. */\n public abstract presentation: PluginPresentationApi\n\n constructor() {}\n}\n\nexport * from \"./core\"\nexport * from \"./design\"\nexport * from \"./entity\"\nexport * from \"./program\"\nexport * from \"./presentation\"\n"],"mappings":"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","names":["z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z","z"]}