@snaptrude/plugin-core 0.9.16 → 0.9.18-edgesetbacks-20261021.1

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 (221) hide show
  1. package/AGENTS.md +231 -231
  2. package/CHANGELOG.md +408 -402
  3. package/CLAUDE.md +11 -11
  4. package/api-manifest.json +1510 -701
  5. package/dist/api/analysis/daylight.d.ts +5 -5
  6. package/dist/api/analysis/solar.d.ts +2 -2
  7. package/dist/api/core/camera/index.d.ts +29 -0
  8. package/dist/api/core/camera/index.d.ts.map +1 -1
  9. package/dist/api/core/geom/create/index.d.ts +7 -1
  10. package/dist/api/core/geom/create/index.d.ts.map +1 -1
  11. package/dist/api/core/geom/update/contour.d.ts +8 -2
  12. package/dist/api/core/geom/update/contour.d.ts.map +1 -1
  13. package/dist/api/core/storeys/index.d.ts +5 -2
  14. package/dist/api/core/storeys/index.d.ts.map +1 -1
  15. package/dist/api/core/zoom/index.d.ts +13 -0
  16. package/dist/api/core/zoom/index.d.ts.map +1 -1
  17. package/dist/api/design/bim.d.ts +299 -0
  18. package/dist/api/design/bim.d.ts.map +1 -0
  19. package/dist/api/design/boolean/index.d.ts +2 -0
  20. package/dist/api/design/boolean/index.d.ts.map +1 -1
  21. package/dist/api/design/catalog.d.ts +320 -0
  22. package/dist/api/design/catalog.d.ts.map +1 -0
  23. package/dist/api/design/create/bulk-items.d.ts +65 -25
  24. package/dist/api/design/create/bulk-items.d.ts.map +1 -1
  25. package/dist/api/design/create/index.d.ts +299 -100
  26. package/dist/api/design/create/index.d.ts.map +1 -1
  27. package/dist/api/design/create/opening-fields.d.ts +13 -12
  28. package/dist/api/design/create/opening-fields.d.ts.map +1 -1
  29. package/dist/api/design/delete/index.d.ts +1 -0
  30. package/dist/api/design/delete/index.d.ts.map +1 -1
  31. package/dist/api/design/doors/index.d.ts +18 -24
  32. package/dist/api/design/doors/index.d.ts.map +1 -1
  33. package/dist/api/design/family.d.ts +813 -35
  34. package/dist/api/design/family.d.ts.map +1 -1
  35. package/dist/api/design/index.d.ts +16 -0
  36. package/dist/api/design/index.d.ts.map +1 -1
  37. package/dist/api/design/networks.d.ts +1703 -0
  38. package/dist/api/design/networks.d.ts.map +1 -0
  39. package/dist/api/design/query/grids.d.ts +2 -2
  40. package/dist/api/design/query/index.d.ts +42 -32
  41. package/dist/api/design/query/index.d.ts.map +1 -1
  42. package/dist/api/design/selection/index.d.ts +10 -10
  43. package/dist/api/design/types/index.d.ts +40 -24
  44. package/dist/api/design/types/index.d.ts.map +1 -1
  45. package/dist/api/design/update/index.d.ts +111 -6
  46. package/dist/api/design/update/index.d.ts.map +1 -1
  47. package/dist/api/design/windows/index.d.ts +8 -8
  48. package/dist/api/design/windows/index.d.ts.map +1 -1
  49. package/dist/api/entity/buildableEnvelope.d.ts +84 -2
  50. package/dist/api/entity/buildableEnvelope.d.ts.map +1 -1
  51. package/dist/api/presentation/aiInspiration.d.ts +10 -10
  52. package/dist/api/presentation/annotate.d.ts +38 -22
  53. package/dist/api/presentation/annotate.d.ts.map +1 -1
  54. package/dist/api/presentation/drawingContract.d.ts +32 -0
  55. package/dist/api/presentation/drawingContract.d.ts.map +1 -0
  56. package/dist/api/presentation/drawings.d.ts +3523 -0
  57. package/dist/api/presentation/drawings.d.ts.map +1 -0
  58. package/dist/api/presentation/export.d.ts +23 -5
  59. package/dist/api/presentation/export.d.ts.map +1 -1
  60. package/dist/api/presentation/index.d.ts +41 -12
  61. package/dist/api/presentation/index.d.ts.map +1 -1
  62. package/dist/api/presentation/placedViews.d.ts +106 -6
  63. package/dist/api/presentation/placedViews.d.ts.map +1 -1
  64. package/dist/api/presentation/sections.d.ts +461 -0
  65. package/dist/api/presentation/sections.d.ts.map +1 -0
  66. package/dist/api/presentation/shapes.d.ts +2 -2
  67. package/dist/api/presentation/sheets.d.ts +175 -19
  68. package/dist/api/presentation/sheets.d.ts.map +1 -1
  69. package/dist/api/presentation/viewPresets.d.ts +222 -0
  70. package/dist/api/presentation/viewPresets.d.ts.map +1 -0
  71. package/dist/api/presentation/views.d.ts +141 -8
  72. package/dist/api/presentation/views.d.ts.map +1 -1
  73. package/dist/api/presentation/walkthroughs.d.ts +6 -6
  74. package/dist/errors/codes.d.ts +3 -1
  75. package/dist/errors/codes.d.ts.map +1 -1
  76. package/dist/index.cjs +3883 -2385
  77. package/dist/index.cjs.map +1 -1
  78. package/dist/index.js +3744 -2385
  79. package/dist/index.js.map +1 -1
  80. package/package.json +1 -1
  81. package/scripts/check-dist-fresh.mjs +22 -22
  82. package/scripts/generate-manifest.mjs +243 -238
  83. package/scripts/generate-manifest.test.mjs +303 -303
  84. package/src/api/analysis/daylight.ts +470 -470
  85. package/src/api/analysis/heatmaps.ts +683 -683
  86. package/src/api/analysis/illuminance.ts +155 -155
  87. package/src/api/analysis/index.ts +61 -61
  88. package/src/api/analysis/shadows.ts +183 -183
  89. package/src/api/analysis/solar.ts +237 -237
  90. package/src/api/analysis/sunlightHours.ts +211 -211
  91. package/src/api/analysis/sunpath.ts +83 -83
  92. package/src/api/analysis/weather.ts +179 -179
  93. package/src/api/core/buildings.ts +485 -485
  94. package/src/api/core/camera/index.ts +696 -667
  95. package/src/api/core/comment/index.ts +376 -376
  96. package/src/api/core/geom/create/index.ts +2139 -2133
  97. package/src/api/core/geom/delete/index.ts +84 -84
  98. package/src/api/core/geom/index.ts +35 -35
  99. package/src/api/core/geom/query/arc.ts +169 -169
  100. package/src/api/core/geom/query/brep.ts +621 -621
  101. package/src/api/core/geom/query/circle.ts +404 -404
  102. package/src/api/core/geom/query/contour.ts +540 -540
  103. package/src/api/core/geom/query/curve.ts +1102 -1102
  104. package/src/api/core/geom/query/edge.ts +130 -130
  105. package/src/api/core/geom/query/face.ts +508 -508
  106. package/src/api/core/geom/query/halfedge.ts +210 -210
  107. package/src/api/core/geom/query/index.ts +63 -63
  108. package/src/api/core/geom/query/profile.ts +473 -473
  109. package/src/api/core/geom/query/vertex.ts +205 -205
  110. package/src/api/core/geom/update/contour.ts +323 -317
  111. package/src/api/core/geom/update/curve.ts +209 -209
  112. package/src/api/core/geom/update/index.ts +29 -29
  113. package/src/api/core/geom/update/profile.ts +379 -379
  114. package/src/api/core/groups.ts +521 -521
  115. package/src/api/core/handles/index.ts +234 -234
  116. package/src/api/core/history/index.ts +84 -84
  117. package/src/api/core/index.ts +99 -99
  118. package/src/api/core/io/export/index.ts +126 -126
  119. package/src/api/core/io/import/index.ts +504 -504
  120. package/src/api/core/io/index.ts +42 -42
  121. package/src/api/core/io/job/index.ts +140 -140
  122. package/src/api/core/io/query/index.ts +71 -71
  123. package/src/api/core/io/terrain/index.ts +360 -360
  124. package/src/api/core/io/underlay/index.ts +705 -705
  125. package/src/api/core/layers.ts +540 -540
  126. package/src/api/core/math/index.ts +20 -20
  127. package/src/api/core/math/quat.ts +172 -172
  128. package/src/api/core/math/vec3.ts +179 -179
  129. package/src/api/core/mode/index.ts +108 -108
  130. package/src/api/core/project/index.ts +479 -479
  131. package/src/api/core/proposals/index.ts +570 -570
  132. package/src/api/core/storeys/index.ts +311 -308
  133. package/src/api/core/storeys/layers.ts +339 -339
  134. package/src/api/core/tags.ts +911 -911
  135. package/src/api/core/units/index.ts +164 -164
  136. package/src/api/core/user.ts +46 -46
  137. package/src/api/core/zoom/index.ts +64 -51
  138. package/src/api/design/bim.ts +210 -0
  139. package/src/api/design/boolean/index.ts +181 -179
  140. package/src/api/design/catalog.ts +203 -0
  141. package/src/api/design/create/bulk-items.ts +294 -254
  142. package/src/api/design/create/grids.ts +137 -137
  143. package/src/api/design/create/index.ts +2178 -1980
  144. package/src/api/design/create/opening-fields.ts +40 -37
  145. package/src/api/design/delete/index.ts +75 -74
  146. package/src/api/design/dimensions.ts +453 -453
  147. package/src/api/design/doors/index.ts +516 -500
  148. package/src/api/design/edit/index.ts +54 -54
  149. package/src/api/design/erase/index.ts +151 -151
  150. package/src/api/design/family.ts +1342 -704
  151. package/src/api/design/furniture/index.ts +319 -319
  152. package/src/api/design/grids.ts +237 -237
  153. package/src/api/design/index.ts +304 -274
  154. package/src/api/design/lock.ts +69 -69
  155. package/src/api/design/materials/index.ts +608 -608
  156. package/src/api/design/networks.ts +607 -0
  157. package/src/api/design/query/geometry/index.ts +319 -319
  158. package/src/api/design/query/grids.ts +197 -197
  159. package/src/api/design/query/index.ts +1236 -1226
  160. package/src/api/design/query/referenceLines.ts +52 -52
  161. package/src/api/design/query/spaces.ts +275 -275
  162. package/src/api/design/selection/index.ts +273 -273
  163. package/src/api/design/shared.ts +40 -40
  164. package/src/api/design/transform/index.ts +254 -254
  165. package/src/api/design/types/index.ts +163 -156
  166. package/src/api/design/update/index.ts +1096 -983
  167. package/src/api/design/visibility.ts +143 -143
  168. package/src/api/design/windows/index.ts +351 -333
  169. package/src/api/entity/buildableEnvelope.ts +397 -322
  170. package/src/api/entity/index.ts +30 -30
  171. package/src/api/entity/referenceLine.ts +235 -235
  172. package/src/api/entity/space.ts +612 -612
  173. package/src/api/entity/story.ts +517 -517
  174. package/src/api/index.ts +47 -47
  175. package/src/api/presentation/aiInspiration.ts +1116 -1116
  176. package/src/api/presentation/annotate.ts +417 -385
  177. package/src/api/presentation/camera.ts +289 -289
  178. package/src/api/presentation/diagrams.ts +194 -194
  179. package/src/api/presentation/drawingContract.ts +70 -0
  180. package/src/api/presentation/drawings.ts +1179 -0
  181. package/src/api/presentation/export.ts +134 -108
  182. package/src/api/presentation/import.ts +159 -159
  183. package/src/api/presentation/index.ts +160 -126
  184. package/src/api/presentation/placedViews.ts +1211 -1120
  185. package/src/api/presentation/sections.ts +420 -0
  186. package/src/api/presentation/shapes.ts +274 -274
  187. package/src/api/presentation/sheets.ts +746 -585
  188. package/src/api/presentation/slideshow.ts +134 -134
  189. package/src/api/presentation/tables.ts +84 -84
  190. package/src/api/presentation/viewPresets.ts +241 -0
  191. package/src/api/presentation/views.ts +742 -673
  192. package/src/api/presentation/walkthroughs.ts +1201 -1201
  193. package/src/api/program/adjacency.ts +164 -164
  194. package/src/api/program/areas.ts +408 -408
  195. package/src/api/program/classification.ts +138 -138
  196. package/src/api/program/cores.ts +83 -83
  197. package/src/api/program/departments.ts +517 -517
  198. package/src/api/program/index.ts +73 -73
  199. package/src/api/program/labels.ts +332 -332
  200. package/src/api/program/layout.ts +422 -422
  201. package/src/api/program/metadata.ts +364 -364
  202. package/src/api/program/metrics.ts +120 -120
  203. package/src/api/program/site.ts +748 -748
  204. package/src/api/program/spreadsheet.ts +2698 -2698
  205. package/src/api/workspace/index.ts +612 -612
  206. package/src/errors/codes.ts +143 -136
  207. package/src/errors/envelope.ts +75 -75
  208. package/src/errors/index.ts +21 -21
  209. package/src/errors/plugin-error.ts +134 -134
  210. package/src/handles.ts +297 -297
  211. package/src/host-utils.ts +67 -67
  212. package/src/index.ts +7 -7
  213. package/src/massParameters.ops.ts +246 -246
  214. package/src/massParameters.ts +427 -427
  215. package/src/types.ts +16 -16
  216. package/test/drawingContract.test.mjs +288 -0
  217. package/test/errors.test.mjs +185 -184
  218. package/test/massParameters.test.mjs +952 -952
  219. package/test/presentationViewSettings.test.mjs +85 -0
  220. package/tsconfig.json +22 -22
  221. package/tsup.config.ts +12 -12
@@ -1,453 +1,453 @@
1
- import * as z from "zod"
2
- import { PluginApiReturn } from "../../types"
3
- import {
4
- ComponentHandle,
5
- DimensionHandle,
6
- Vec3Components,
7
- Vec3Handle,
8
- } from "../../handles"
9
-
10
- /**
11
- * Dimension lines (Measuring Tape) — the measurement annotations the Measuring
12
- * Tape tool leaves in the 3D scene, NOT an entity's width/height/depth
13
- * properties (for those see `design.windows.getDimensions`,
14
- * `design.create.staircase`'s `dimensions`, or `design.query.measure`).
15
- *
16
- * A dimension line is a scene object: two endpoints anchored to the geometry
17
- * they were measured on, an offset that pushes the drawn line clear of the
18
- * span, and a label showing the distance in the project's units. Because the
19
- * endpoints are anchored, the line follows its host when the host is moved,
20
- * edited, or resized, and it is removed with the host when the host is deleted.
21
- * Dimension lines are storey-scoped, render in both plan and 3D, and are drawn
22
- * into Present-mode sheets (style them with
23
- * `presentation.placedViews.updateStyles(shapeId, "Dimension", …)`).
24
- *
25
- * **Units.** Every length here — `offset` and the record's `length` — is in
26
- * **Babylon units** (BU), the engine's storage unit: 1 BU = 10 in = 0.254 m.
27
- * Convert with `core.units.convert(value, from, await core.units.getBabylonType())`.
28
- *
29
- * **Offset convention.** `options.offset` is a **signed** distance in BU:
30
- * positive pushes the drawn line to the **left** of the `from` → `to`
31
- * direction in plan (`cross(up, direction)`), negative to the right. It
32
- * defaults to `3.937` BU (1 m). The placement mode is always `"across"` (the
33
- * tape tool's perpendicular mode), which re-perpendicularises when the host
34
- * geometry is edited.
35
- *
36
- * Every mutator here (`create`, `delete`, `hide`, `show`) commits through the
37
- * engine's command manager, so each call is a single undo entry, is autosaved,
38
- * and replays to collaborators.
39
- *
40
- * Accessed via `snaptrude.design.dimensions`.
41
- */
42
- export abstract class PluginDesignDimensionsApi {
43
- constructor() {}
44
-
45
- /**
46
- * Draw one dimension line between two world points, anchored to a component.
47
- *
48
- * `anchor` is **required**: the endpoints are stored relative to the anchor's
49
- * mesh, and only component-anchored dimension lines survive a reload. A
50
- * free-point dimension anchors to a scene helper mesh whose id is not stable
51
- * across reloads, so it is dropped or corrupted when the project is reopened
52
- * — the host therefore rejects a non-component anchor rather than writing a
53
- * record that silently disappears. Pass `options.anchorTo` to anchor the
54
- * second endpoint to a different component (it defaults to `anchor`).
55
- *
56
- * The dimension is created flat (never plan-projected) so the same call
57
- * produces the same record whatever the current camera; it still draws in
58
- * plan.
59
- *
60
- * @param from - World-space first endpoint.
61
- * @param to - World-space second endpoint.
62
- * @param anchor - The component the first endpoint is anchored to (required).
63
- * @param options - `anchorTo` (component for the second endpoint; defaults to
64
- * `anchor`), `offset` (signed perpendicular offset in Babylon units,
65
- * positive = left of the `from` → `to` direction in plan; default `3.937`
66
- * BU = 1 m).
67
- * @returns The new dimension line's {@linkcode DimensionHandle}.
68
- * @throws `VALIDATION` for malformed arguments or a degenerate span (`from`
69
- * and `to` closer than the engine's minimum); `HANDLE_INVALID` for an
70
- * unknown `anchor` / `anchorTo`; `PRECONDITION_FAILED` when the anchor is
71
- * outside the active proposal or the editor is not mounted;
72
- * `METHOD_NOT_PERMITTED` when plugin writes are disabled.
73
- *
74
- * @examplePrompt Dimension every wall on level 2
75
- * @examplePrompt Add a dimension line along this wall
76
- * @examplePrompt Measure the width of this room and label it on the plan
77
- *
78
- * # Example
79
- * ```ts
80
- * const { design, core } = snaptrude
81
- * const v = core.math.vec3
82
- * const curve = core.geom.query.curve
83
- * for (const wall of await design.query.listWalls({ storeys: [2] })) {
84
- * const cl = await design.query.geometry.getCenterline(wall)
85
- * if (!cl) continue
86
- * const a = await curve.getStartPoint(cl)
87
- * const b = await curve.getEndPoint(cl)
88
- * await design.dimensions.create(
89
- * await v.new(a.x, a.y, a.z),
90
- * await v.new(b.x, b.y, b.z),
91
- * wall,
92
- * )
93
- * }
94
- * ```
95
- */
96
- public abstract create(
97
- from: Vec3Handle,
98
- to: Vec3Handle,
99
- anchor: ComponentHandle,
100
- options?: { anchorTo?: ComponentHandle; offset?: number },
101
- ): PluginApiReturn<DimensionHandle>
102
-
103
- /**
104
- * List the dimension lines in the project as full records.
105
- *
106
- * Filters combine with AND. `storeys` keeps only the dimensions on those
107
- * storey numbers, `anchors` only the ones anchored to those components
108
- * (matching either endpoint, and matching an instanced anchor's source mesh
109
- * too), `isHidden` only the ones whose user Hide flag equals the value given.
110
- *
111
- * Dimension lines drawn by the Measuring Tape onto a scene helper mesh rather
112
- * than a component come back with `anchor: null` and are not proposal-scoped.
113
- *
114
- * @param options - `storeys`, `anchors`, `isHidden` filters (all optional,
115
- * ANDed).
116
- * @returns The matching {@linkcode PluginDimensionLine} records (`[]` when
117
- * nothing matches).
118
- * @throws `VALIDATION` for malformed filters; `HANDLE_INVALID` for an unknown
119
- * handle in `anchors`.
120
- *
121
- * @examplePrompt List all the dimension lines in this model
122
- * @examplePrompt Which dimensions are on level 3?
123
- * @examplePrompt Flag any dimension line shorter than 600 mm
124
- *
125
- * @performance Array read — one host round-trip returns every record. Filter
126
- * in one call rather than calling `get` per dimension.
127
- *
128
- * # Example
129
- * ```ts
130
- * const units = snaptrude.core.units
131
- * const min = await units.convert(600, "millimeters", await units.getBabylonType())
132
- * const short = (await snaptrude.design.dimensions.list()).filter(
133
- * (d) => d.length < min,
134
- * )
135
- * console.log(short.map((d) => `${d.label} on storey ${d.storey}`))
136
- * ```
137
- */
138
- public abstract list(options?: {
139
- storeys?: number[]
140
- anchors?: ComponentHandle[]
141
- isHidden?: boolean
142
- }): PluginApiReturn<PluginDimensionLine[]>
143
-
144
- /**
145
- * Read one dimension line by handle.
146
- *
147
- * Returns `null` — rather than throwing — when the dimension no longer
148
- * exists, so a handle kept across a delete or an undo can be polled safely.
149
- *
150
- * @param dimension - The dimension line to read.
151
- * @returns Its {@linkcode PluginDimensionLine} record, or `null` if it is
152
- * gone.
153
- * @throws `VALIDATION` if `dimension` is not a non-empty id string.
154
- *
155
- * @examplePrompt Read the dimension line I just created
156
- * @examplePrompt How long is this dimension and what does its label say?
157
- * @examplePrompt Check whether that dimension line still exists
158
- *
159
- * # Example
160
- * ```ts
161
- * const dim = await snaptrude.design.dimensions.get(handle)
162
- * if (dim) console.log(dim.label, dim.length, dim.storey)
163
- * ```
164
- */
165
- public abstract get(
166
- dimension: DimensionHandle,
167
- ): PluginApiReturn<PluginDimensionLine | null>
168
-
169
- /**
170
- * Delete dimension lines — the same hard removal as selecting them and
171
- * pressing Delete. Undoable as a **single** entry for the whole batch.
172
- *
173
- * Deleted handles are stale afterwards: {@linkcode
174
- * PluginDesignDimensionsApi.get} returns `null` for them and the other
175
- * mutators throw `HANDLE_INVALID`.
176
- *
177
- * @param dimensions - The dimension lines to delete (at least one — an empty
178
- * array is a caller error, not a no-op).
179
- * @returns The dimensions that were deleted, as
180
- * {@linkcode PluginDimensionsChangeResult}.
181
- * @throws `VALIDATION` for an empty or malformed array; `HANDLE_INVALID` if
182
- * any handle is unknown (the whole call rejects before anything is
183
- * deleted); `PRECONDITION_FAILED` if any dimension's anchor is outside the
184
- * active proposal; `METHOD_NOT_PERMITTED` when plugin writes are disabled.
185
- *
186
- * @examplePrompt Remove all dimension lines
187
- * @examplePrompt Delete the dimensions on this wall
188
- * @examplePrompt Clear the measurements I added to level 2
189
- *
190
- * @performance Array API — pass the whole set in one call (one host
191
- * round-trip, one undo entry). Never loop this per dimension.
192
- *
193
- * # Example
194
- * ```ts
195
- * const dims = snaptrude.design.dimensions
196
- * const onWall = await dims.list({ anchors: [wall] })
197
- * if (onWall.length > 0) await dims.delete(onWall.map((d) => d.id))
198
- * ```
199
- */
200
- public abstract delete(
201
- dimensions: DimensionHandle[],
202
- ): PluginApiReturn<PluginDimensionsChangeResult>
203
-
204
- /**
205
- * Hide dimension lines from the viewport — the same as the right-click "Hide"
206
- * action (it sets the user Hide flag, `isHidden`). Undoable. Already-hidden
207
- * dimensions are skipped and are not reported in `affected`.
208
- *
209
- * @param dimensions - The dimension lines to hide.
210
- * @returns The dimensions actually hidden, as
211
- * {@linkcode PluginDimensionsChangeResult} — already-hidden inputs are
212
- * omitted, so `affected` can be shorter than the input.
213
- * @throws `VALIDATION` for a malformed array; `HANDLE_INVALID` if any handle
214
- * is unknown; `PRECONDITION_FAILED` if any dimension's anchor is outside
215
- * the active proposal; `METHOD_NOT_PERMITTED` when plugin writes are
216
- * disabled.
217
- *
218
- * @examplePrompt Hide the dimensions on this storey
219
- * @examplePrompt Hide every dimension line while I present
220
- * @examplePrompt Temporarily hide the measurements on level 3
221
- *
222
- * @performance Array API — one host round-trip and one undo entry for the
223
- * whole set.
224
- *
225
- * # Example
226
- * ```ts
227
- * const dims = snaptrude.design.dimensions
228
- * const onLevel3 = await dims.list({ storeys: [3] })
229
- * const { affected } = await dims.hide(onLevel3.map((d) => d.id))
230
- * ```
231
- */
232
- public abstract hide(
233
- dimensions: DimensionHandle[],
234
- ): PluginApiReturn<PluginDimensionsChangeResult>
235
-
236
- /**
237
- * Reveal hidden dimension lines — clear the user Hide flag, the inverse of
238
- * {@linkcode PluginDesignDimensionsApi.hide}. Undoable. Already-visible
239
- * dimensions are skipped and are not reported in `affected`.
240
- *
241
- * Clearing the flag does not guarantee the dimension is on screen: a
242
- * dimension whose anchor component is itself hidden stays off screen with
243
- * `isHidden: false` and `isVisible: false`.
244
- *
245
- * @param dimensions - The dimension lines to reveal.
246
- * @returns The dimensions actually revealed, as
247
- * {@linkcode PluginDimensionsChangeResult} — already-visible inputs are
248
- * omitted, so `affected` can be shorter than the input.
249
- * @throws `VALIDATION` for a malformed array; `HANDLE_INVALID` if any handle
250
- * is unknown; `PRECONDITION_FAILED` if any dimension's anchor is outside
251
- * the active proposal; `METHOD_NOT_PERMITTED` when plugin writes are
252
- * disabled.
253
- *
254
- * @examplePrompt Show the dimension lines again
255
- * @examplePrompt Unhide all the hidden dimensions
256
- * @examplePrompt Bring back the measurements I hid on this storey
257
- *
258
- * @performance Array API — one host round-trip and one undo entry for the
259
- * whole set.
260
- *
261
- * # Example
262
- * ```ts
263
- * const dims = snaptrude.design.dimensions
264
- * const hidden = await dims.list({ isHidden: true })
265
- * await dims.show(hidden.map((d) => d.id))
266
- * ```
267
- */
268
- public abstract show(
269
- dimensions: DimensionHandle[],
270
- ): PluginApiReturn<PluginDimensionsChangeResult>
271
- }
272
-
273
- /**
274
- * How a dimension line's drawn offset is constrained.
275
- *
276
- * - `"across"` — perpendicular to the span (the tape tool's default, and what
277
- * every plugin-created dimension uses); re-perpendicularises when the host
278
- * geometry is edited.
279
- * - `"x"` / `"y"` / `"z"` — the offset is locked to that world axis.
280
- * - `"none"` — no placement mode recorded (a plain world-space offset).
281
- */
282
- export const PluginDimensionPlacement = z.enum([
283
- "across",
284
- "x",
285
- "y",
286
- "z",
287
- "none",
288
- ])
289
- export type PluginDimensionPlacement = z.infer<typeof PluginDimensionPlacement>
290
-
291
- /**
292
- * One dimension line (Measuring Tape annotation). Lengths are in **Babylon
293
- * units** (1 BU = 0.254 m — convert with `core.units.convert`).
294
- *
295
- * | Property | Type | Description |
296
- * |---|---|---|
297
- * | `id` | {@linkcode DimensionHandle} | The dimension line's handle |
298
- * | `from` | {@linkcode Vec3Components} | Live world position of the first endpoint |
299
- * | `to` | {@linkcode Vec3Components} | Live world position of the second endpoint |
300
- * | `length` | `number` | Straight-line distance between `from` and `to`, in Babylon units |
301
- * | `label` | `string` | The text drawn on the canvas, in the project's units (a bare number for metric/inch projects, `27' 7"` style for feet-inches). For a span whose x, y and z all differ the drawn line is the plan projection, so `label` reads the horizontal distance while `length` is the true 3D one |
302
- * | `offset` | {@linkcode Vec3Components} | World vector from the measured span to the drawn line |
303
- * | `placement` | {@linkcode PluginDimensionPlacement} | How that offset is constrained |
304
- * | `anchor` | {@linkcode ComponentHandle}` \| null` | Component the first endpoint is anchored to; `null` for a free point or a non-component host mesh |
305
- * | `anchorTo` | {@linkcode ComponentHandle}` \| null` | Component the second endpoint is anchored to; equals `anchor` when both endpoints share a host |
306
- * | `storey` | `number` | Storey the dimension belongs to |
307
- * | `buildingId` | `string \| null` | Building it belongs to, when it has one |
308
- * | `isHidden` | `boolean` | The user Hide flag (what `hide` / `show` toggle) |
309
- * | `isVisible` | `boolean` | Whether it is actually drawn — `false` when hidden, and also when an anchor component is hidden |
310
- * | `isPlanProjected` | `boolean` | Whether it is drawn flattened onto the storey base (Measuring Tape dimensions drawn in 2D are; plugin-created ones never are) |
311
- */
312
- export const PluginDimensionLine = z.object({
313
- id: DimensionHandle,
314
- from: Vec3Components,
315
- to: Vec3Components,
316
- length: z.number(),
317
- label: z.string(),
318
- offset: Vec3Components,
319
- placement: PluginDimensionPlacement,
320
- anchor: ComponentHandle.nullable(),
321
- anchorTo: ComponentHandle.nullable(),
322
- storey: z.number(),
323
- buildingId: z.string().nullable(),
324
- isHidden: z.boolean(),
325
- isVisible: z.boolean(),
326
- isPlanProjected: z.boolean(),
327
- })
328
- export type PluginDimensionLine = z.infer<typeof PluginDimensionLine>
329
-
330
- /**
331
- * Result of every `design.dimensions` mutation that takes a batch
332
- * ({@linkcode PluginDesignDimensionsApi.delete} /
333
- * {@linkcode PluginDesignDimensionsApi.hide} /
334
- * {@linkcode PluginDesignDimensionsApi.show}) — the dimensions actually
335
- * affected. `hide` / `show` skip dimensions already in the target state, so
336
- * `affected` can be shorter than the input; `delete` echoes the whole batch.
337
- * Failures throw (the RPC rejects); there is no `Result<>` monad in the SDK.
338
- *
339
- * | Property | Type | Description |
340
- * |---|---|---|
341
- * | `affected` | {@linkcode DimensionHandle}`[]` | The dimension lines the call changed |
342
- */
343
- export const PluginDimensionsChangeResult = z.object({
344
- affected: z.array(DimensionHandle),
345
- })
346
- export type PluginDimensionsChangeResult = z.infer<
347
- typeof PluginDimensionsChangeResult
348
- >
349
-
350
- /**
351
- * Arguments for {@linkcode PluginDesignDimensionsApi.create} (options
352
- * flattened).
353
- *
354
- * | Property | Type | Description |
355
- * |---|---|---|
356
- * | `from` | {@linkcode Vec3Handle} | World-space first endpoint |
357
- * | `to` | {@linkcode Vec3Handle} | World-space second endpoint |
358
- * | `anchor` | {@linkcode ComponentHandle} | Component the first endpoint anchors to (required — free-point dimensions do not survive a reload) |
359
- * | `anchorTo` | {@linkcode ComponentHandle}? | Component for the second endpoint (default: `anchor`) |
360
- * | `offset` | `number`? | Signed perpendicular offset in Babylon units, positive = left of the `from` → `to` direction in plan (default `3.937` BU = 1 m) |
361
- *
362
- * TRANSPORT: positional args — validated host-side as this object.
363
- */
364
- export const PluginDesignDimensionsCreateArgs = z.object({
365
- from: Vec3Handle,
366
- to: Vec3Handle,
367
- anchor: ComponentHandle,
368
- anchorTo: ComponentHandle.optional(),
369
- offset: z.number().finite().optional(),
370
- })
371
- export type PluginDesignDimensionsCreateArgs = z.infer<
372
- typeof PluginDesignDimensionsCreateArgs
373
- >
374
-
375
- /**
376
- * Arguments for {@linkcode PluginDesignDimensionsApi.list} (options flattened).
377
- * Filters combine with AND; omitting all of them lists every dimension line.
378
- *
379
- * | Property | Type | Description |
380
- * |---|---|---|
381
- * | `storeys` | `number[]`? | Only dimensions on these storey numbers |
382
- * | `anchors` | {@linkcode ComponentHandle}`[]`? | Only dimensions anchored to these components (either endpoint) |
383
- * | `isHidden` | `boolean`? | user-hidden flag === |
384
- */
385
- export const PluginDesignDimensionsListArgs = z.object({
386
- storeys: z.array(z.number()).optional(),
387
- anchors: z.array(ComponentHandle).optional(),
388
- isHidden: z.boolean().optional(),
389
- })
390
- export type PluginDesignDimensionsListArgs = z.infer<
391
- typeof PluginDesignDimensionsListArgs
392
- >
393
-
394
- /**
395
- * Arguments for {@linkcode PluginDesignDimensionsApi.get}.
396
- *
397
- * | Property | Type | Description |
398
- * |---|---|---|
399
- * | `dimension` | {@linkcode DimensionHandle} | The dimension line to read |
400
- */
401
- export const PluginDesignDimensionsGetArgs = z.object({
402
- dimension: DimensionHandle,
403
- })
404
- export type PluginDesignDimensionsGetArgs = z.infer<
405
- typeof PluginDesignDimensionsGetArgs
406
- >
407
-
408
- /**
409
- * Arguments for {@linkcode PluginDesignDimensionsApi.delete}.
410
- *
411
- * `.min(1)` mirrors {@linkcode PluginDesignDeleteEntitiesArgs}: an empty delete
412
- * is a caller error, not a no-op.
413
- *
414
- * | Property | Type | Description |
415
- * |---|---|---|
416
- * | `dimensions` | {@linkcode DimensionHandle}`[]` | Dimension lines to delete. Unknown handles reject the whole call (fail-fast). |
417
- */
418
- export const PluginDesignDimensionsDeleteArgs = z.object({
419
- dimensions: z.array(DimensionHandle).min(1),
420
- })
421
- export type PluginDesignDimensionsDeleteArgs = z.infer<
422
- typeof PluginDesignDimensionsDeleteArgs
423
- >
424
-
425
- /**
426
- * Arguments for {@linkcode PluginDesignDimensionsApi.hide}. An empty array is
427
- * allowed and is a no-op (mirroring {@linkcode PluginDesignVisibilityHideArgs}).
428
- *
429
- * | Property | Type | Description |
430
- * |---|---|---|
431
- * | `dimensions` | {@linkcode DimensionHandle}`[]` | Dimension lines to hide |
432
- */
433
- export const PluginDesignDimensionsHideArgs = z.object({
434
- dimensions: z.array(DimensionHandle),
435
- })
436
- export type PluginDesignDimensionsHideArgs = z.infer<
437
- typeof PluginDesignDimensionsHideArgs
438
- >
439
-
440
- /**
441
- * Arguments for {@linkcode PluginDesignDimensionsApi.show}. An empty array is
442
- * allowed and is a no-op.
443
- *
444
- * | Property | Type | Description |
445
- * |---|---|---|
446
- * | `dimensions` | {@linkcode DimensionHandle}`[]` | Dimension lines to reveal |
447
- */
448
- export const PluginDesignDimensionsShowArgs = z.object({
449
- dimensions: z.array(DimensionHandle),
450
- })
451
- export type PluginDesignDimensionsShowArgs = z.infer<
452
- typeof PluginDesignDimensionsShowArgs
453
- >
1
+ import * as z from "zod"
2
+ import { PluginApiReturn } from "../../types"
3
+ import {
4
+ ComponentHandle,
5
+ DimensionHandle,
6
+ Vec3Components,
7
+ Vec3Handle,
8
+ } from "../../handles"
9
+
10
+ /**
11
+ * Dimension lines (Measuring Tape) — the measurement annotations the Measuring
12
+ * Tape tool leaves in the 3D scene, NOT an entity's width/height/depth
13
+ * properties (for those see `design.windows.getDimensions`,
14
+ * `design.create.staircase`'s `dimensions`, or `design.query.measure`).
15
+ *
16
+ * A dimension line is a scene object: two endpoints anchored to the geometry
17
+ * they were measured on, an offset that pushes the drawn line clear of the
18
+ * span, and a label showing the distance in the project's units. Because the
19
+ * endpoints are anchored, the line follows its host when the host is moved,
20
+ * edited, or resized, and it is removed with the host when the host is deleted.
21
+ * Dimension lines are storey-scoped, render in both plan and 3D, and are drawn
22
+ * into Present-mode sheets (style them with
23
+ * `presentation.placedViews.updateStyles(shapeId, "Dimension", …)`).
24
+ *
25
+ * **Units.** Every length here — `offset` and the record's `length` — is in
26
+ * **Babylon units** (BU), the engine's storage unit: 1 BU = 10 in = 0.254 m.
27
+ * Convert with `core.units.convert(value, from, await core.units.getBabylonType())`.
28
+ *
29
+ * **Offset convention.** `options.offset` is a **signed** distance in BU:
30
+ * positive pushes the drawn line to the **left** of the `from` → `to`
31
+ * direction in plan (`cross(up, direction)`), negative to the right. It
32
+ * defaults to `3.937` BU (1 m). The placement mode is always `"across"` (the
33
+ * tape tool's perpendicular mode), which re-perpendicularises when the host
34
+ * geometry is edited.
35
+ *
36
+ * Every mutator here (`create`, `delete`, `hide`, `show`) commits through the
37
+ * engine's command manager, so each call is a single undo entry, is autosaved,
38
+ * and replays to collaborators.
39
+ *
40
+ * Accessed via `snaptrude.design.dimensions`.
41
+ */
42
+ export abstract class PluginDesignDimensionsApi {
43
+ constructor() {}
44
+
45
+ /**
46
+ * Draw one dimension line between two world points, anchored to a component.
47
+ *
48
+ * `anchor` is **required**: the endpoints are stored relative to the anchor's
49
+ * mesh, and only component-anchored dimension lines survive a reload. A
50
+ * free-point dimension anchors to a scene helper mesh whose id is not stable
51
+ * across reloads, so it is dropped or corrupted when the project is reopened
52
+ * — the host therefore rejects a non-component anchor rather than writing a
53
+ * record that silently disappears. Pass `options.anchorTo` to anchor the
54
+ * second endpoint to a different component (it defaults to `anchor`).
55
+ *
56
+ * The dimension is created flat (never plan-projected) so the same call
57
+ * produces the same record whatever the current camera; it still draws in
58
+ * plan.
59
+ *
60
+ * @param from - World-space first endpoint.
61
+ * @param to - World-space second endpoint.
62
+ * @param anchor - The component the first endpoint is anchored to (required).
63
+ * @param options - `anchorTo` (component for the second endpoint; defaults to
64
+ * `anchor`), `offset` (signed perpendicular offset in Babylon units,
65
+ * positive = left of the `from` → `to` direction in plan; default `3.937`
66
+ * BU = 1 m).
67
+ * @returns The new dimension line's {@linkcode DimensionHandle}.
68
+ * @throws `VALIDATION` for malformed arguments or a degenerate span (`from`
69
+ * and `to` closer than the engine's minimum); `HANDLE_INVALID` for an
70
+ * unknown `anchor` / `anchorTo`; `PRECONDITION_FAILED` when the anchor is
71
+ * outside the active proposal or the editor is not mounted;
72
+ * `METHOD_NOT_PERMITTED` when plugin writes are disabled.
73
+ *
74
+ * @examplePrompt Dimension every wall on level 2
75
+ * @examplePrompt Add a dimension line along this wall
76
+ * @examplePrompt Measure the width of this room and label it on the plan
77
+ *
78
+ * # Example
79
+ * ```ts
80
+ * const { design, core } = snaptrude
81
+ * const v = core.math.vec3
82
+ * const curve = core.geom.query.curve
83
+ * for (const wall of await design.query.listWalls({ storeys: [2] })) {
84
+ * const cl = await design.query.geometry.getCenterline(wall)
85
+ * if (!cl) continue
86
+ * const a = await curve.getStartPoint(cl)
87
+ * const b = await curve.getEndPoint(cl)
88
+ * await design.dimensions.create(
89
+ * await v.new(a.x, a.y, a.z),
90
+ * await v.new(b.x, b.y, b.z),
91
+ * wall,
92
+ * )
93
+ * }
94
+ * ```
95
+ */
96
+ public abstract create(
97
+ from: Vec3Handle,
98
+ to: Vec3Handle,
99
+ anchor: ComponentHandle,
100
+ options?: { anchorTo?: ComponentHandle; offset?: number },
101
+ ): PluginApiReturn<DimensionHandle>
102
+
103
+ /**
104
+ * List the dimension lines in the project as full records.
105
+ *
106
+ * Filters combine with AND. `storeys` keeps only the dimensions on those
107
+ * storey numbers, `anchors` only the ones anchored to those components
108
+ * (matching either endpoint, and matching an instanced anchor's source mesh
109
+ * too), `isHidden` only the ones whose user Hide flag equals the value given.
110
+ *
111
+ * Dimension lines drawn by the Measuring Tape onto a scene helper mesh rather
112
+ * than a component come back with `anchor: null` and are not proposal-scoped.
113
+ *
114
+ * @param options - `storeys`, `anchors`, `isHidden` filters (all optional,
115
+ * ANDed).
116
+ * @returns The matching {@linkcode PluginDimensionLine} records (`[]` when
117
+ * nothing matches).
118
+ * @throws `VALIDATION` for malformed filters; `HANDLE_INVALID` for an unknown
119
+ * handle in `anchors`.
120
+ *
121
+ * @examplePrompt List all the dimension lines in this model
122
+ * @examplePrompt Which dimensions are on level 3?
123
+ * @examplePrompt Flag any dimension line shorter than 600 mm
124
+ *
125
+ * @performance Array read — one host round-trip returns every record. Filter
126
+ * in one call rather than calling `get` per dimension.
127
+ *
128
+ * # Example
129
+ * ```ts
130
+ * const units = snaptrude.core.units
131
+ * const min = await units.convert(600, "millimeters", await units.getBabylonType())
132
+ * const short = (await snaptrude.design.dimensions.list()).filter(
133
+ * (d) => d.length < min,
134
+ * )
135
+ * console.log(short.map((d) => `${d.label} on storey ${d.storey}`))
136
+ * ```
137
+ */
138
+ public abstract list(options?: {
139
+ storeys?: number[]
140
+ anchors?: ComponentHandle[]
141
+ isHidden?: boolean
142
+ }): PluginApiReturn<PluginDimensionLine[]>
143
+
144
+ /**
145
+ * Read one dimension line by handle.
146
+ *
147
+ * Returns `null` — rather than throwing — when the dimension no longer
148
+ * exists, so a handle kept across a delete or an undo can be polled safely.
149
+ *
150
+ * @param dimension - The dimension line to read.
151
+ * @returns Its {@linkcode PluginDimensionLine} record, or `null` if it is
152
+ * gone.
153
+ * @throws `VALIDATION` if `dimension` is not a non-empty id string.
154
+ *
155
+ * @examplePrompt Read the dimension line I just created
156
+ * @examplePrompt How long is this dimension and what does its label say?
157
+ * @examplePrompt Check whether that dimension line still exists
158
+ *
159
+ * # Example
160
+ * ```ts
161
+ * const dim = await snaptrude.design.dimensions.get(handle)
162
+ * if (dim) console.log(dim.label, dim.length, dim.storey)
163
+ * ```
164
+ */
165
+ public abstract get(
166
+ dimension: DimensionHandle,
167
+ ): PluginApiReturn<PluginDimensionLine | null>
168
+
169
+ /**
170
+ * Delete dimension lines — the same hard removal as selecting them and
171
+ * pressing Delete. Undoable as a **single** entry for the whole batch.
172
+ *
173
+ * Deleted handles are stale afterwards: {@linkcode
174
+ * PluginDesignDimensionsApi.get} returns `null` for them and the other
175
+ * mutators throw `HANDLE_INVALID`.
176
+ *
177
+ * @param dimensions - The dimension lines to delete (at least one — an empty
178
+ * array is a caller error, not a no-op).
179
+ * @returns The dimensions that were deleted, as
180
+ * {@linkcode PluginDimensionsChangeResult}.
181
+ * @throws `VALIDATION` for an empty or malformed array; `HANDLE_INVALID` if
182
+ * any handle is unknown (the whole call rejects before anything is
183
+ * deleted); `PRECONDITION_FAILED` if any dimension's anchor is outside the
184
+ * active proposal; `METHOD_NOT_PERMITTED` when plugin writes are disabled.
185
+ *
186
+ * @examplePrompt Remove all dimension lines
187
+ * @examplePrompt Delete the dimensions on this wall
188
+ * @examplePrompt Clear the measurements I added to level 2
189
+ *
190
+ * @performance Array API — pass the whole set in one call (one host
191
+ * round-trip, one undo entry). Never loop this per dimension.
192
+ *
193
+ * # Example
194
+ * ```ts
195
+ * const dims = snaptrude.design.dimensions
196
+ * const onWall = await dims.list({ anchors: [wall] })
197
+ * if (onWall.length > 0) await dims.delete(onWall.map((d) => d.id))
198
+ * ```
199
+ */
200
+ public abstract delete(
201
+ dimensions: DimensionHandle[],
202
+ ): PluginApiReturn<PluginDimensionsChangeResult>
203
+
204
+ /**
205
+ * Hide dimension lines from the viewport — the same as the right-click "Hide"
206
+ * action (it sets the user Hide flag, `isHidden`). Undoable. Already-hidden
207
+ * dimensions are skipped and are not reported in `affected`.
208
+ *
209
+ * @param dimensions - The dimension lines to hide.
210
+ * @returns The dimensions actually hidden, as
211
+ * {@linkcode PluginDimensionsChangeResult} — already-hidden inputs are
212
+ * omitted, so `affected` can be shorter than the input.
213
+ * @throws `VALIDATION` for a malformed array; `HANDLE_INVALID` if any handle
214
+ * is unknown; `PRECONDITION_FAILED` if any dimension's anchor is outside
215
+ * the active proposal; `METHOD_NOT_PERMITTED` when plugin writes are
216
+ * disabled.
217
+ *
218
+ * @examplePrompt Hide the dimensions on this storey
219
+ * @examplePrompt Hide every dimension line while I present
220
+ * @examplePrompt Temporarily hide the measurements on level 3
221
+ *
222
+ * @performance Array API — one host round-trip and one undo entry for the
223
+ * whole set.
224
+ *
225
+ * # Example
226
+ * ```ts
227
+ * const dims = snaptrude.design.dimensions
228
+ * const onLevel3 = await dims.list({ storeys: [3] })
229
+ * const { affected } = await dims.hide(onLevel3.map((d) => d.id))
230
+ * ```
231
+ */
232
+ public abstract hide(
233
+ dimensions: DimensionHandle[],
234
+ ): PluginApiReturn<PluginDimensionsChangeResult>
235
+
236
+ /**
237
+ * Reveal hidden dimension lines — clear the user Hide flag, the inverse of
238
+ * {@linkcode PluginDesignDimensionsApi.hide}. Undoable. Already-visible
239
+ * dimensions are skipped and are not reported in `affected`.
240
+ *
241
+ * Clearing the flag does not guarantee the dimension is on screen: a
242
+ * dimension whose anchor component is itself hidden stays off screen with
243
+ * `isHidden: false` and `isVisible: false`.
244
+ *
245
+ * @param dimensions - The dimension lines to reveal.
246
+ * @returns The dimensions actually revealed, as
247
+ * {@linkcode PluginDimensionsChangeResult} — already-visible inputs are
248
+ * omitted, so `affected` can be shorter than the input.
249
+ * @throws `VALIDATION` for a malformed array; `HANDLE_INVALID` if any handle
250
+ * is unknown; `PRECONDITION_FAILED` if any dimension's anchor is outside
251
+ * the active proposal; `METHOD_NOT_PERMITTED` when plugin writes are
252
+ * disabled.
253
+ *
254
+ * @examplePrompt Show the dimension lines again
255
+ * @examplePrompt Unhide all the hidden dimensions
256
+ * @examplePrompt Bring back the measurements I hid on this storey
257
+ *
258
+ * @performance Array API — one host round-trip and one undo entry for the
259
+ * whole set.
260
+ *
261
+ * # Example
262
+ * ```ts
263
+ * const dims = snaptrude.design.dimensions
264
+ * const hidden = await dims.list({ isHidden: true })
265
+ * await dims.show(hidden.map((d) => d.id))
266
+ * ```
267
+ */
268
+ public abstract show(
269
+ dimensions: DimensionHandle[],
270
+ ): PluginApiReturn<PluginDimensionsChangeResult>
271
+ }
272
+
273
+ /**
274
+ * How a dimension line's drawn offset is constrained.
275
+ *
276
+ * - `"across"` — perpendicular to the span (the tape tool's default, and what
277
+ * every plugin-created dimension uses); re-perpendicularises when the host
278
+ * geometry is edited.
279
+ * - `"x"` / `"y"` / `"z"` — the offset is locked to that world axis.
280
+ * - `"none"` — no placement mode recorded (a plain world-space offset).
281
+ */
282
+ export const PluginDimensionPlacement = z.enum([
283
+ "across",
284
+ "x",
285
+ "y",
286
+ "z",
287
+ "none",
288
+ ])
289
+ export type PluginDimensionPlacement = z.infer<typeof PluginDimensionPlacement>
290
+
291
+ /**
292
+ * One dimension line (Measuring Tape annotation). Lengths are in **Babylon
293
+ * units** (1 BU = 0.254 m — convert with `core.units.convert`).
294
+ *
295
+ * | Property | Type | Description |
296
+ * |---|---|---|
297
+ * | `id` | {@linkcode DimensionHandle} | The dimension line's handle |
298
+ * | `from` | {@linkcode Vec3Components} | Live world position of the first endpoint |
299
+ * | `to` | {@linkcode Vec3Components} | Live world position of the second endpoint |
300
+ * | `length` | `number` | Straight-line distance between `from` and `to`, in Babylon units |
301
+ * | `label` | `string` | The text drawn on the canvas, in the project's units (a bare number for metric/inch projects, `27' 7"` style for feet-inches). For a span whose x, y and z all differ the drawn line is the plan projection, so `label` reads the horizontal distance while `length` is the true 3D one |
302
+ * | `offset` | {@linkcode Vec3Components} | World vector from the measured span to the drawn line |
303
+ * | `placement` | {@linkcode PluginDimensionPlacement} | How that offset is constrained |
304
+ * | `anchor` | {@linkcode ComponentHandle}` \| null` | Component the first endpoint is anchored to; `null` for a free point or a non-component host mesh |
305
+ * | `anchorTo` | {@linkcode ComponentHandle}` \| null` | Component the second endpoint is anchored to; equals `anchor` when both endpoints share a host |
306
+ * | `storey` | `number` | Storey the dimension belongs to |
307
+ * | `buildingId` | `string \| null` | Building it belongs to, when it has one |
308
+ * | `isHidden` | `boolean` | The user Hide flag (what `hide` / `show` toggle) |
309
+ * | `isVisible` | `boolean` | Whether it is actually drawn — `false` when hidden, and also when an anchor component is hidden |
310
+ * | `isPlanProjected` | `boolean` | Whether it is drawn flattened onto the storey base (Measuring Tape dimensions drawn in 2D are; plugin-created ones never are) |
311
+ */
312
+ export const PluginDimensionLine = z.object({
313
+ id: DimensionHandle,
314
+ from: Vec3Components,
315
+ to: Vec3Components,
316
+ length: z.number(),
317
+ label: z.string(),
318
+ offset: Vec3Components,
319
+ placement: PluginDimensionPlacement,
320
+ anchor: ComponentHandle.nullable(),
321
+ anchorTo: ComponentHandle.nullable(),
322
+ storey: z.number(),
323
+ buildingId: z.string().nullable(),
324
+ isHidden: z.boolean(),
325
+ isVisible: z.boolean(),
326
+ isPlanProjected: z.boolean(),
327
+ })
328
+ export type PluginDimensionLine = z.infer<typeof PluginDimensionLine>
329
+
330
+ /**
331
+ * Result of every `design.dimensions` mutation that takes a batch
332
+ * ({@linkcode PluginDesignDimensionsApi.delete} /
333
+ * {@linkcode PluginDesignDimensionsApi.hide} /
334
+ * {@linkcode PluginDesignDimensionsApi.show}) — the dimensions actually
335
+ * affected. `hide` / `show` skip dimensions already in the target state, so
336
+ * `affected` can be shorter than the input; `delete` echoes the whole batch.
337
+ * Failures throw (the RPC rejects); there is no `Result<>` monad in the SDK.
338
+ *
339
+ * | Property | Type | Description |
340
+ * |---|---|---|
341
+ * | `affected` | {@linkcode DimensionHandle}`[]` | The dimension lines the call changed |
342
+ */
343
+ export const PluginDimensionsChangeResult = z.object({
344
+ affected: z.array(DimensionHandle),
345
+ })
346
+ export type PluginDimensionsChangeResult = z.infer<
347
+ typeof PluginDimensionsChangeResult
348
+ >
349
+
350
+ /**
351
+ * Arguments for {@linkcode PluginDesignDimensionsApi.create} (options
352
+ * flattened).
353
+ *
354
+ * | Property | Type | Description |
355
+ * |---|---|---|
356
+ * | `from` | {@linkcode Vec3Handle} | World-space first endpoint |
357
+ * | `to` | {@linkcode Vec3Handle} | World-space second endpoint |
358
+ * | `anchor` | {@linkcode ComponentHandle} | Component the first endpoint anchors to (required — free-point dimensions do not survive a reload) |
359
+ * | `anchorTo` | {@linkcode ComponentHandle}? | Component for the second endpoint (default: `anchor`) |
360
+ * | `offset` | `number`? | Signed perpendicular offset in Babylon units, positive = left of the `from` → `to` direction in plan (default `3.937` BU = 1 m) |
361
+ *
362
+ * TRANSPORT: positional args — validated host-side as this object.
363
+ */
364
+ export const PluginDesignDimensionsCreateArgs = z.object({
365
+ from: Vec3Handle,
366
+ to: Vec3Handle,
367
+ anchor: ComponentHandle,
368
+ anchorTo: ComponentHandle.optional(),
369
+ offset: z.number().finite().optional(),
370
+ })
371
+ export type PluginDesignDimensionsCreateArgs = z.infer<
372
+ typeof PluginDesignDimensionsCreateArgs
373
+ >
374
+
375
+ /**
376
+ * Arguments for {@linkcode PluginDesignDimensionsApi.list} (options flattened).
377
+ * Filters combine with AND; omitting all of them lists every dimension line.
378
+ *
379
+ * | Property | Type | Description |
380
+ * |---|---|---|
381
+ * | `storeys` | `number[]`? | Only dimensions on these storey numbers |
382
+ * | `anchors` | {@linkcode ComponentHandle}`[]`? | Only dimensions anchored to these components (either endpoint) |
383
+ * | `isHidden` | `boolean`? | user-hidden flag === |
384
+ */
385
+ export const PluginDesignDimensionsListArgs = z.object({
386
+ storeys: z.array(z.number()).optional(),
387
+ anchors: z.array(ComponentHandle).optional(),
388
+ isHidden: z.boolean().optional(),
389
+ })
390
+ export type PluginDesignDimensionsListArgs = z.infer<
391
+ typeof PluginDesignDimensionsListArgs
392
+ >
393
+
394
+ /**
395
+ * Arguments for {@linkcode PluginDesignDimensionsApi.get}.
396
+ *
397
+ * | Property | Type | Description |
398
+ * |---|---|---|
399
+ * | `dimension` | {@linkcode DimensionHandle} | The dimension line to read |
400
+ */
401
+ export const PluginDesignDimensionsGetArgs = z.object({
402
+ dimension: DimensionHandle,
403
+ })
404
+ export type PluginDesignDimensionsGetArgs = z.infer<
405
+ typeof PluginDesignDimensionsGetArgs
406
+ >
407
+
408
+ /**
409
+ * Arguments for {@linkcode PluginDesignDimensionsApi.delete}.
410
+ *
411
+ * `.min(1)` mirrors {@linkcode PluginDesignDeleteEntitiesArgs}: an empty delete
412
+ * is a caller error, not a no-op.
413
+ *
414
+ * | Property | Type | Description |
415
+ * |---|---|---|
416
+ * | `dimensions` | {@linkcode DimensionHandle}`[]` | Dimension lines to delete. Unknown handles reject the whole call (fail-fast). |
417
+ */
418
+ export const PluginDesignDimensionsDeleteArgs = z.object({
419
+ dimensions: z.array(DimensionHandle).min(1),
420
+ })
421
+ export type PluginDesignDimensionsDeleteArgs = z.infer<
422
+ typeof PluginDesignDimensionsDeleteArgs
423
+ >
424
+
425
+ /**
426
+ * Arguments for {@linkcode PluginDesignDimensionsApi.hide}. An empty array is
427
+ * allowed and is a no-op (mirroring {@linkcode PluginDesignVisibilityHideArgs}).
428
+ *
429
+ * | Property | Type | Description |
430
+ * |---|---|---|
431
+ * | `dimensions` | {@linkcode DimensionHandle}`[]` | Dimension lines to hide |
432
+ */
433
+ export const PluginDesignDimensionsHideArgs = z.object({
434
+ dimensions: z.array(DimensionHandle),
435
+ })
436
+ export type PluginDesignDimensionsHideArgs = z.infer<
437
+ typeof PluginDesignDimensionsHideArgs
438
+ >
439
+
440
+ /**
441
+ * Arguments for {@linkcode PluginDesignDimensionsApi.show}. An empty array is
442
+ * allowed and is a no-op.
443
+ *
444
+ * | Property | Type | Description |
445
+ * |---|---|---|
446
+ * | `dimensions` | {@linkcode DimensionHandle}`[]` | Dimension lines to reveal |
447
+ */
448
+ export const PluginDesignDimensionsShowArgs = z.object({
449
+ dimensions: z.array(DimensionHandle),
450
+ })
451
+ export type PluginDesignDimensionsShowArgs = z.infer<
452
+ typeof PluginDesignDimensionsShowArgs
453
+ >