@snaptrude/plugin-core 0.9.17 → 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 (219) hide show
  1. package/AGENTS.md +231 -231
  2. package/CHANGELOG.md +408 -408
  3. package/CLAUDE.md +11 -11
  4. package/api-manifest.json +1428 -712
  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 +32 -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/shapes.d.ts +2 -2
  65. package/dist/api/presentation/sheets.d.ts +175 -19
  66. package/dist/api/presentation/sheets.d.ts.map +1 -1
  67. package/dist/api/presentation/viewPresets.d.ts +222 -0
  68. package/dist/api/presentation/viewPresets.d.ts.map +1 -0
  69. package/dist/api/presentation/views.d.ts +141 -8
  70. package/dist/api/presentation/views.d.ts.map +1 -1
  71. package/dist/api/presentation/walkthroughs.d.ts +6 -6
  72. package/dist/errors/codes.d.ts +3 -1
  73. package/dist/errors/codes.d.ts.map +1 -1
  74. package/dist/index.cjs +3831 -2444
  75. package/dist/index.cjs.map +1 -1
  76. package/dist/index.js +3705 -2444
  77. package/dist/index.js.map +1 -1
  78. package/package.json +1 -1
  79. package/scripts/check-dist-fresh.mjs +22 -22
  80. package/scripts/generate-manifest.mjs +243 -238
  81. package/scripts/generate-manifest.test.mjs +303 -303
  82. package/src/api/analysis/daylight.ts +470 -470
  83. package/src/api/analysis/heatmaps.ts +683 -683
  84. package/src/api/analysis/illuminance.ts +155 -155
  85. package/src/api/analysis/index.ts +61 -61
  86. package/src/api/analysis/shadows.ts +183 -183
  87. package/src/api/analysis/solar.ts +237 -237
  88. package/src/api/analysis/sunlightHours.ts +211 -211
  89. package/src/api/analysis/sunpath.ts +83 -83
  90. package/src/api/analysis/weather.ts +179 -179
  91. package/src/api/core/buildings.ts +485 -485
  92. package/src/api/core/camera/index.ts +696 -667
  93. package/src/api/core/comment/index.ts +376 -376
  94. package/src/api/core/geom/create/index.ts +2139 -2133
  95. package/src/api/core/geom/delete/index.ts +84 -84
  96. package/src/api/core/geom/index.ts +35 -35
  97. package/src/api/core/geom/query/arc.ts +169 -169
  98. package/src/api/core/geom/query/brep.ts +621 -621
  99. package/src/api/core/geom/query/circle.ts +404 -404
  100. package/src/api/core/geom/query/contour.ts +540 -540
  101. package/src/api/core/geom/query/curve.ts +1102 -1102
  102. package/src/api/core/geom/query/edge.ts +130 -130
  103. package/src/api/core/geom/query/face.ts +508 -508
  104. package/src/api/core/geom/query/halfedge.ts +210 -210
  105. package/src/api/core/geom/query/index.ts +63 -63
  106. package/src/api/core/geom/query/profile.ts +473 -473
  107. package/src/api/core/geom/query/vertex.ts +205 -205
  108. package/src/api/core/geom/update/contour.ts +323 -317
  109. package/src/api/core/geom/update/curve.ts +209 -209
  110. package/src/api/core/geom/update/index.ts +29 -29
  111. package/src/api/core/geom/update/profile.ts +379 -379
  112. package/src/api/core/groups.ts +521 -521
  113. package/src/api/core/handles/index.ts +234 -234
  114. package/src/api/core/history/index.ts +84 -84
  115. package/src/api/core/index.ts +99 -99
  116. package/src/api/core/io/export/index.ts +126 -126
  117. package/src/api/core/io/import/index.ts +504 -504
  118. package/src/api/core/io/index.ts +42 -42
  119. package/src/api/core/io/job/index.ts +140 -140
  120. package/src/api/core/io/query/index.ts +71 -71
  121. package/src/api/core/io/terrain/index.ts +360 -360
  122. package/src/api/core/io/underlay/index.ts +705 -705
  123. package/src/api/core/layers.ts +540 -540
  124. package/src/api/core/math/index.ts +20 -20
  125. package/src/api/core/math/quat.ts +172 -172
  126. package/src/api/core/math/vec3.ts +179 -179
  127. package/src/api/core/mode/index.ts +108 -108
  128. package/src/api/core/project/index.ts +479 -479
  129. package/src/api/core/proposals/index.ts +570 -570
  130. package/src/api/core/storeys/index.ts +311 -308
  131. package/src/api/core/storeys/layers.ts +339 -339
  132. package/src/api/core/tags.ts +911 -911
  133. package/src/api/core/units/index.ts +164 -164
  134. package/src/api/core/user.ts +46 -46
  135. package/src/api/core/zoom/index.ts +64 -51
  136. package/src/api/design/bim.ts +210 -0
  137. package/src/api/design/boolean/index.ts +181 -179
  138. package/src/api/design/catalog.ts +203 -0
  139. package/src/api/design/create/bulk-items.ts +294 -254
  140. package/src/api/design/create/grids.ts +137 -137
  141. package/src/api/design/create/index.ts +2178 -1980
  142. package/src/api/design/create/opening-fields.ts +40 -37
  143. package/src/api/design/delete/index.ts +75 -74
  144. package/src/api/design/dimensions.ts +453 -453
  145. package/src/api/design/doors/index.ts +516 -500
  146. package/src/api/design/edit/index.ts +54 -54
  147. package/src/api/design/erase/index.ts +151 -151
  148. package/src/api/design/family.ts +1342 -704
  149. package/src/api/design/furniture/index.ts +319 -319
  150. package/src/api/design/grids.ts +237 -237
  151. package/src/api/design/index.ts +304 -274
  152. package/src/api/design/lock.ts +69 -69
  153. package/src/api/design/materials/index.ts +608 -608
  154. package/src/api/design/networks.ts +607 -0
  155. package/src/api/design/query/geometry/index.ts +319 -319
  156. package/src/api/design/query/grids.ts +197 -197
  157. package/src/api/design/query/index.ts +1236 -1226
  158. package/src/api/design/query/referenceLines.ts +52 -52
  159. package/src/api/design/query/spaces.ts +275 -275
  160. package/src/api/design/selection/index.ts +273 -273
  161. package/src/api/design/shared.ts +40 -40
  162. package/src/api/design/transform/index.ts +254 -254
  163. package/src/api/design/types/index.ts +163 -156
  164. package/src/api/design/update/index.ts +1096 -983
  165. package/src/api/design/visibility.ts +143 -143
  166. package/src/api/design/windows/index.ts +351 -333
  167. package/src/api/entity/buildableEnvelope.ts +397 -322
  168. package/src/api/entity/index.ts +30 -30
  169. package/src/api/entity/referenceLine.ts +235 -235
  170. package/src/api/entity/space.ts +612 -612
  171. package/src/api/entity/story.ts +517 -517
  172. package/src/api/index.ts +47 -47
  173. package/src/api/presentation/aiInspiration.ts +1116 -1116
  174. package/src/api/presentation/annotate.ts +417 -385
  175. package/src/api/presentation/camera.ts +289 -289
  176. package/src/api/presentation/diagrams.ts +194 -194
  177. package/src/api/presentation/drawingContract.ts +70 -0
  178. package/src/api/presentation/drawings.ts +1179 -0
  179. package/src/api/presentation/export.ts +134 -108
  180. package/src/api/presentation/import.ts +159 -159
  181. package/src/api/presentation/index.ts +160 -135
  182. package/src/api/presentation/placedViews.ts +1211 -1120
  183. package/src/api/presentation/sections.ts +420 -420
  184. package/src/api/presentation/shapes.ts +274 -274
  185. package/src/api/presentation/sheets.ts +746 -585
  186. package/src/api/presentation/slideshow.ts +134 -134
  187. package/src/api/presentation/tables.ts +84 -84
  188. package/src/api/presentation/viewPresets.ts +241 -0
  189. package/src/api/presentation/views.ts +742 -673
  190. package/src/api/presentation/walkthroughs.ts +1201 -1201
  191. package/src/api/program/adjacency.ts +164 -164
  192. package/src/api/program/areas.ts +408 -408
  193. package/src/api/program/classification.ts +138 -138
  194. package/src/api/program/cores.ts +83 -83
  195. package/src/api/program/departments.ts +517 -517
  196. package/src/api/program/index.ts +73 -73
  197. package/src/api/program/labels.ts +332 -332
  198. package/src/api/program/layout.ts +422 -422
  199. package/src/api/program/metadata.ts +364 -364
  200. package/src/api/program/metrics.ts +120 -120
  201. package/src/api/program/site.ts +748 -748
  202. package/src/api/program/spreadsheet.ts +2698 -2698
  203. package/src/api/workspace/index.ts +612 -612
  204. package/src/errors/codes.ts +143 -136
  205. package/src/errors/envelope.ts +75 -75
  206. package/src/errors/index.ts +21 -21
  207. package/src/errors/plugin-error.ts +134 -134
  208. package/src/handles.ts +297 -297
  209. package/src/host-utils.ts +67 -67
  210. package/src/index.ts +7 -7
  211. package/src/massParameters.ops.ts +246 -246
  212. package/src/massParameters.ts +427 -427
  213. package/src/types.ts +16 -16
  214. package/test/drawingContract.test.mjs +288 -0
  215. package/test/errors.test.mjs +185 -184
  216. package/test/massParameters.test.mjs +952 -952
  217. package/test/presentationViewSettings.test.mjs +85 -0
  218. package/tsconfig.json +22 -22
  219. package/tsup.config.ts +12 -12
@@ -1,360 +1,360 @@
1
- import * as z from "zod"
2
- import { PluginApiReturn } from "../../../../types"
3
- import { TerrainHandle } from "../../../../handles"
4
-
5
- /**
6
- * Terrain — inspect and manage the project's site terrain (the singleton created
7
- * by `core.io.import.terrain`).
8
- *
9
- * There is at most one terrain per project. These methods read and edit it: the
10
- * vertical **datum**, elevation/satellite layers, opacity, the cut/fill report,
11
- * and removal. All edits are undoable.
12
- *
13
- * ## Datum
14
- * The **datum** is the terrain's vertical position relative to where it was
15
- * imported. {@link PluginCoreIoTerrainApi.setDatum} shifts the whole terrain
16
- * vertically by a **relative** offset (each call moves it further — calls are
17
- * cumulative, not absolute); {@link PluginCoreIoTerrainApi.getDatum} reads the
18
- * current vertical offset from the imported position.
19
- *
20
- * Accessed via `snaptrude.core.io.terrain`.
21
- */
22
- export abstract class PluginCoreIoTerrainApi {
23
- constructor() {}
24
-
25
- /**
26
- * Whether the project has a site terrain.
27
- *
28
- * @examplePrompt Does this project have site terrain?
29
- * @examplePrompt Is there a terrain imported?
30
- * @examplePrompt Check if the site topography exists
31
- * @examplePrompt Has a terrain been added yet?
32
- *
33
- * # Example
34
- * ```ts
35
- * if (!(await snaptrude.core.io.terrain.exists())) {
36
- * await snaptrude.core.io.import.terrain(40.7128, -74.006, 300, 300)
37
- * }
38
- * ```
39
- */
40
- public abstract exists(): PluginApiReturn<boolean>
41
-
42
- /**
43
- * Resolve the project's terrain handle, or `null` if there is none. The same
44
- * handle {@link core.io.import.terrain} returns — use it to obtain the handle
45
- * without re-importing.
46
- *
47
- * @examplePrompt Get the terrain handle
48
- * @examplePrompt Give me the site terrain
49
- * @examplePrompt Fetch the current terrain
50
- * @examplePrompt Return the topography handle if it exists
51
- */
52
- public abstract get(): PluginApiReturn<TerrainHandle | null>
53
-
54
- /**
55
- * Read the terrain's current vertical position (world Y, internal units).
56
- * `null` if there is no terrain. Import places the terrain so its highest
57
- * point sits at `y = 0`, so a never-shifted terrain reads a negative
58
- * baseline, not `0`; each {@link PluginCoreIoTerrainApi.setDatum} shift
59
- * moves this value.
60
- *
61
- * @examplePrompt What's the terrain's datum?
62
- * @examplePrompt Read the current site elevation reference
63
- * @examplePrompt Get the terrain vertical offset
64
- * @examplePrompt How far has the datum been shifted?
65
- */
66
- public abstract getDatum(): PluginApiReturn<number | null>
67
-
68
- /**
69
- * Shift the terrain's **datum** — move the whole terrain vertically DOWN by
70
- * `offset` (internal units) from its current position; pass a negative value to
71
- * raise it. Undoable.
72
- *
73
- * **Relative and cumulative**, not absolute: `setDatum(5)` called twice shifts
74
- * the terrain down by 10 total, it does not settle at a fixed level. Read the
75
- * terrain's resulting vertical position (world Y — not the accumulated
76
- * shift) back with {@link PluginCoreIoTerrainApi.getDatum}.
77
- *
78
- * @param offset - How far to shift the terrain down, in internal units
79
- * (negative raises it).
80
- * @throws if writes are disabled, there is no terrain, or the terrain is
81
- * **locked** (unlock it in the app first).
82
- *
83
- * @examplePrompt Shift the terrain datum down by 12
84
- * @examplePrompt Lower the site terrain by 10
85
- * @examplePrompt Raise the terrain a little
86
- * @examplePrompt Nudge the terrain datum down
87
- *
88
- * # Example
89
- * ```ts
90
- * await snaptrude.core.io.terrain.setDatum(12) // shift terrain down by 12 (relative)
91
- * ```
92
- */
93
- public abstract setDatum(offset: number): PluginApiReturn<void>
94
-
95
- /**
96
- * Delete the site terrain. Undoable.
97
- *
98
- * @throws if writes are disabled, there is no terrain, or the terrain is
99
- * **locked** (unlock it in the app first).
100
- *
101
- * @examplePrompt Delete the site terrain
102
- * @examplePrompt Remove the topography
103
- * @examplePrompt Clear the imported site
104
- * @examplePrompt Get rid of the terrain
105
- */
106
- public abstract delete(): PluginApiReturn<void>
107
-
108
- /**
109
- * The terrain cut/fill earthwork report — cut, fill, and net volumes — or
110
- * `null` if there is no terrain.
111
- *
112
- * @examplePrompt What are the cut and fill volumes for the site?
113
- * @examplePrompt Get the terrain earthwork report
114
- * @examplePrompt How much cut and fill does the grading need?
115
- * @examplePrompt Show the net volume of the terrain edits
116
- *
117
- * # Example
118
- * ```ts
119
- * const r = await snaptrude.core.io.terrain.getReport()
120
- * if (r) console.log(`cut ${r.cutVolume}, fill ${r.fillVolume}, net ${r.netVolume}`)
121
- * ```
122
- */
123
- public abstract getReport(): PluginApiReturn<TerrainReport | null>
124
-
125
- /** Whether terrain elevation (DEM height) is on. `null` if no terrain. */
126
- public abstract isElevationEnabled(): PluginApiReturn<boolean | null>
127
- /**
128
- * Turn terrain elevation (DEM height) ON — a real 3D topography surface. Undoable.
129
- * @throws if writes are disabled, there is no terrain, or the terrain is
130
- * **locked** (unlock it in the app first).
131
- * @examplePrompt Turn on terrain elevation
132
- * @examplePrompt Enable the site heightmap
133
- * @examplePrompt Make the terrain 3D
134
- * @examplePrompt Show the topography relief
135
- */
136
- public abstract enableElevation(): PluginApiReturn<void>
137
- /**
138
- * Turn terrain elevation OFF — flatten to a plane. Undoable.
139
- * @throws if writes are disabled, there is no terrain, or the terrain is
140
- * **locked** (unlock it in the app first).
141
- * @examplePrompt Flatten the terrain
142
- * @examplePrompt Turn off site elevation
143
- * @examplePrompt Disable the heightmap
144
- * @examplePrompt Make the terrain flat
145
- */
146
- public abstract disableElevation(): PluginApiReturn<void>
147
-
148
- /** Whether satellite imagery is draped on the terrain. `null` if no terrain. */
149
- public abstract isSatelliteEnabled(): PluginApiReturn<boolean | null>
150
- /**
151
- * Turn satellite imagery ON. Undoable.
152
- * @throws if writes are disabled, there is no terrain, or the terrain is
153
- * **locked** (unlock it in the app first).
154
- * @examplePrompt Show satellite imagery on the site
155
- * @examplePrompt Enable the satellite texture
156
- * @examplePrompt Turn on aerial imagery
157
- * @examplePrompt Drape satellite over the terrain
158
- */
159
- public abstract enableSatellite(): PluginApiReturn<void>
160
- /**
161
- * Turn satellite imagery OFF. Undoable.
162
- * @throws if writes are disabled, there is no terrain, or the terrain is
163
- * **locked** (unlock it in the app first).
164
- * @examplePrompt Hide the satellite imagery
165
- * @examplePrompt Turn off the aerial texture
166
- * @examplePrompt Disable satellite on the site
167
- * @examplePrompt Remove the satellite drape
168
- */
169
- public abstract disableSatellite(): PluginApiReturn<void>
170
-
171
- /**
172
- * Replace the terrain surface with a caller-supplied triangle mesh. Undoable
173
- * (one step), and the replacement persists with the project. The returned
174
- * promise resolves only after the surface is fully applied and recorded —
175
- * it is safe to toggle terrain resolution or read the surface back the
176
- * moment it resolves.
177
- *
178
- * `positions` is a flat `[x, y, z, …]` array in **world space** — the same
179
- * frame `design.query.geometry.getTriangulatedMeshes` reads — so a
180
- * read-modify-write round trip needs no conversion. `indices` is a flat
181
- * triangle list into `positions` (three indices per triangle). A
182
- * predominantly down-facing surface is flipped automatically (reported in
183
- * `warnings`), and zero-area sliver triangles are tolerated and counted.
184
- *
185
- * **What survives the replacement:** the datum, geolocation, opacity, lock
186
- * state, and the elevation/satellite toggles. The map/satellite texture is
187
- * re-projected onto the new surface from above (best effort — alignment is
188
- * approximate, reported in `warnings`). **What resets:** cut/fill history
189
- * and the earthwork report — the replaced surface starts with a clean
190
- * grading slate.
191
- *
192
- * Limits: at most 500,000 triangles and 500,000 vertices; every coordinate
193
- * must be finite and within the scene bound.
194
- *
195
- * @param positions - Flat `[x, y, z, …]` world-space vertex positions.
196
- * @param indices - Flat triangle list into `positions`.
197
- * @param units - `"world"` (default): coordinates are raw internal units;
198
- * `"meters"`: coordinates are metres and are converted on the way in.
199
- * @param options - Optional {@linkcode PluginTerrainReplaceMeshOptions}:
200
- * optimistic-concurrency expectations (`expectedTerrain`,
201
- * `expectedModelRevision`), `preserve` opt-outs, idempotent replay via
202
- * `clientMutationId`, and the `coordinateSpace`/`baseline` declarations.
203
- * @throws if writes are disabled, there is no terrain (import one first),
204
- * the terrain is **locked**, the mesh fails validation (non-finite or
205
- * out-of-bound coordinates, bad indices, degenerate-only geometry, over
206
- * the size caps), `expectedTerrain` does not match the live terrain, or
207
- * `expectedModelRevision` is stale.
208
- *
209
- * @examplePrompt Replace the terrain with this surveyed mesh
210
- * @examplePrompt Flatten a building pad into the site surface
211
- * @examplePrompt Load a custom DEM surface onto the terrain
212
- * @examplePrompt Regrade the terrain from these points
213
- *
214
- * # Example
215
- * ```ts
216
- * // Projects with no terrain yet: import first, then replace.
217
- * if (!(await snaptrude.core.io.terrain.exists())) {
218
- * await snaptrude.core.io.import.terrain(40.7128, -74.006, 300, 300)
219
- * }
220
- * const result = await snaptrude.core.io.terrain.replaceMesh(
221
- * positions, // [x0, y0, z0, x1, y1, z1, …] — world space
222
- * indices, // [a0, b0, c0, a1, b1, c1, …]
223
- * "meters",
224
- * {
225
- * coordinateSpace: "world",
226
- * expectedTerrain: await snaptrude.core.io.terrain.get(),
227
- * baseline: "make-replacement-original",
228
- * preserve: { datum: true, geolocation: true, satellite: true, material: true },
229
- * clientMutationId: "survey-2026-08-05-r1",
230
- * },
231
- * )
232
- * // result.modelRevision — pass back as expectedModelRevision on the next call
233
- * ```
234
- */
235
- public abstract replaceMesh(
236
- positions: number[],
237
- indices: number[],
238
- units?: "world" | "meters",
239
- options?: PluginTerrainReplaceMeshOptions,
240
- ): PluginApiReturn<PluginTerrainReplaceMeshResult>
241
-
242
- /** Read the terrain opacity, `0`..`1`, or `null` if no terrain. */
243
- public abstract getOpacity(): PluginApiReturn<number | null>
244
- /**
245
- * Set the terrain opacity (`0` transparent .. `1` opaque). Undoable.
246
- * @param opacity - Target opacity, `0`..`1`.
247
- * @throws if writes are disabled, there is no terrain, or the terrain is
248
- * **locked** (unlock it in the app first).
249
- * @examplePrompt Fade the terrain to 50%
250
- * @examplePrompt Make the site semi-transparent
251
- * @examplePrompt Set terrain opacity to 0.3
252
- * @examplePrompt Dim the topography
253
- *
254
- * # Example
255
- * ```ts
256
- * await snaptrude.core.io.terrain.setOpacity(0.5)
257
- * ```
258
- */
259
- public abstract setOpacity(opacity: number): PluginApiReturn<void>
260
- }
261
-
262
- /**
263
- * Terrain cut/fill earthwork report. Volumes are in the **project's display
264
- * volume unit** (what the UI shows), not internal units.
265
- *
266
- * | Property | Type | Description |
267
- * |---|---|---|
268
- * | `cutVolume` | `number` | Total excavated (cut) volume |
269
- * | `fillVolume` | `number` | Total added (fill) volume |
270
- * | `netVolume` | `number` | Net volume (`fill − cut`) |
271
- */
272
- export const TerrainReport = z.object({
273
- cutVolume: z.number(),
274
- fillVolume: z.number(),
275
- netVolume: z.number(),
276
- })
277
- export type TerrainReport = z.infer<typeof TerrainReport>
278
-
279
- /**
280
- * Result of {@link PluginCoreIoTerrainApi.replaceMesh}.
281
- *
282
- * | Property | Type | Description |
283
- * |---|---|---|
284
- * | `terrain` | `TerrainHandle` | The terrain (unchanged singleton handle) |
285
- * | `modelRevision` | `number` | Session-scoped terrain-mesh revision after this replace — pass back as `expectedModelRevision` for compare-and-swap semantics |
286
- * | `vertexCount` | `number` | Vertices in the applied mesh |
287
- * | `triangleCount` | `number` | Triangles in the applied mesh |
288
- * | `warnings` | `string[]` | Non-fatal notes: winding flipped, sliver triangles, approximate texture re-projection |
289
- */
290
- export type PluginTerrainReplaceMeshResult = {
291
- terrain: TerrainHandle
292
- modelRevision: number
293
- vertexCount: number
294
- triangleCount: number
295
- warnings: string[]
296
- }
297
-
298
- /**
299
- * Options for {@link PluginCoreIoTerrainApi.replaceMesh}.
300
- *
301
- * | Property | Type | Description |
302
- * |---|---|---|
303
- * | `coordinateSpace` | `"world"`? | Declares the input frame. `world` is the only supported space (the same frame `getTriangulatedMeshes` reads) |
304
- * | `expectedTerrain` | `TerrainHandle`? | Optimistic check: throws `HANDLE_INVALID` if the live terrain is not this handle (session-scoped — handles do not survive reloads) |
305
- * | `expectedModelRevision` | `number`? | Optimistic check against the session terrain-mesh revision (starts at `0`, increments per successful `replaceMesh`; the result returns the new value). Stale → `PRECONDITION_FAILED` with the current revision in `details` |
306
- * | `baseline` | `"make-replacement-original"`? | Declares replacement semantics. This is the only (and default) behavior: the replacement becomes the persisted surface; the app's terrain Reset restores the original map heightmap as the escape hatch |
307
- * | `preserve` | object? | Opt-outs, all defaulting `true`. `datum: false` resets the terrain transform (authored coordinates become the local frame). `satellite: false` switches the drape off after the replace. `material: false` skips texture re-projection — the whole surface takes the ground material. `geolocation: false` is rejected (`VALIDATION`): geolocation is always preserved in this version |
308
- * | `clientMutationId` | `string`? | Session-scoped idempotency: a repeated call with the same id returns the original result without re-executing |
309
- */
310
- export const PluginTerrainReplaceMeshOptions = z
311
- .object({
312
- coordinateSpace: z.literal("world").optional(),
313
- expectedTerrain: z.string().min(1).optional(),
314
- expectedModelRevision: z.number().int().nonnegative().optional(),
315
- baseline: z.literal("make-replacement-original").optional(),
316
- preserve: z
317
- .object({
318
- datum: z.boolean().optional(),
319
- geolocation: z.boolean().optional(),
320
- satellite: z.boolean().optional(),
321
- material: z.boolean().optional(),
322
- })
323
- .strict()
324
- .optional(),
325
- clientMutationId: z.string().min(1).max(128).optional(),
326
- })
327
- .strict()
328
- export type PluginTerrainReplaceMeshOptions = z.infer<typeof PluginTerrainReplaceMeshOptions>
329
-
330
- /**
331
- * Arguments for {@link PluginCoreIoTerrainApi.replaceMesh}. The caps are the
332
- * plugin surface's explicit payload ceiling: 500k vertices / 500k triangles.
333
- */
334
- export const PluginTerrainReplaceMeshArgs = z.object({
335
- positions: z
336
- .array(z.number().finite())
337
- .min(9)
338
- .max(1_500_000)
339
- .refine((a) => a.length % 3 === 0, {
340
- message: "positions must be a flat [x, y, z, …] array (length a multiple of 3)",
341
- }),
342
- indices: z
343
- .array(z.number().int().nonnegative())
344
- .min(3)
345
- .max(1_500_000)
346
- .refine((a) => a.length % 3 === 0, {
347
- message: "indices must be a flat triangle list (length a multiple of 3)",
348
- }),
349
- units: z.enum(["world", "meters"]).optional(),
350
- options: PluginTerrainReplaceMeshOptions.optional(),
351
- })
352
- export type PluginTerrainReplaceMeshArgs = z.infer<typeof PluginTerrainReplaceMeshArgs>
353
-
354
- /** Arguments for {@link PluginCoreIoTerrainApi.setDatum}. */
355
- export const PluginTerrainSetDatumArgs = z.object({ offset: z.number().finite() })
356
- export type PluginTerrainSetDatumArgs = z.infer<typeof PluginTerrainSetDatumArgs>
357
-
358
- /** Arguments for {@link PluginCoreIoTerrainApi.setOpacity}. */
359
- export const PluginTerrainSetOpacityArgs = z.object({ opacity: z.number().min(0).max(1) })
360
- export type PluginTerrainSetOpacityArgs = z.infer<typeof PluginTerrainSetOpacityArgs>
1
+ import * as z from "zod"
2
+ import { PluginApiReturn } from "../../../../types"
3
+ import { TerrainHandle } from "../../../../handles"
4
+
5
+ /**
6
+ * Terrain — inspect and manage the project's site terrain (the singleton created
7
+ * by `core.io.import.terrain`).
8
+ *
9
+ * There is at most one terrain per project. These methods read and edit it: the
10
+ * vertical **datum**, elevation/satellite layers, opacity, the cut/fill report,
11
+ * and removal. All edits are undoable.
12
+ *
13
+ * ## Datum
14
+ * The **datum** is the terrain's vertical position relative to where it was
15
+ * imported. {@link PluginCoreIoTerrainApi.setDatum} shifts the whole terrain
16
+ * vertically by a **relative** offset (each call moves it further — calls are
17
+ * cumulative, not absolute); {@link PluginCoreIoTerrainApi.getDatum} reads the
18
+ * current vertical offset from the imported position.
19
+ *
20
+ * Accessed via `snaptrude.core.io.terrain`.
21
+ */
22
+ export abstract class PluginCoreIoTerrainApi {
23
+ constructor() {}
24
+
25
+ /**
26
+ * Whether the project has a site terrain.
27
+ *
28
+ * @examplePrompt Does this project have site terrain?
29
+ * @examplePrompt Is there a terrain imported?
30
+ * @examplePrompt Check if the site topography exists
31
+ * @examplePrompt Has a terrain been added yet?
32
+ *
33
+ * # Example
34
+ * ```ts
35
+ * if (!(await snaptrude.core.io.terrain.exists())) {
36
+ * await snaptrude.core.io.import.terrain(40.7128, -74.006, 300, 300)
37
+ * }
38
+ * ```
39
+ */
40
+ public abstract exists(): PluginApiReturn<boolean>
41
+
42
+ /**
43
+ * Resolve the project's terrain handle, or `null` if there is none. The same
44
+ * handle {@link core.io.import.terrain} returns — use it to obtain the handle
45
+ * without re-importing.
46
+ *
47
+ * @examplePrompt Get the terrain handle
48
+ * @examplePrompt Give me the site terrain
49
+ * @examplePrompt Fetch the current terrain
50
+ * @examplePrompt Return the topography handle if it exists
51
+ */
52
+ public abstract get(): PluginApiReturn<TerrainHandle | null>
53
+
54
+ /**
55
+ * Read the terrain's current vertical position (world Y, internal units).
56
+ * `null` if there is no terrain. Import places the terrain so its highest
57
+ * point sits at `y = 0`, so a never-shifted terrain reads a negative
58
+ * baseline, not `0`; each {@link PluginCoreIoTerrainApi.setDatum} shift
59
+ * moves this value.
60
+ *
61
+ * @examplePrompt What's the terrain's datum?
62
+ * @examplePrompt Read the current site elevation reference
63
+ * @examplePrompt Get the terrain vertical offset
64
+ * @examplePrompt How far has the datum been shifted?
65
+ */
66
+ public abstract getDatum(): PluginApiReturn<number | null>
67
+
68
+ /**
69
+ * Shift the terrain's **datum** — move the whole terrain vertically DOWN by
70
+ * `offset` (internal units) from its current position; pass a negative value to
71
+ * raise it. Undoable.
72
+ *
73
+ * **Relative and cumulative**, not absolute: `setDatum(5)` called twice shifts
74
+ * the terrain down by 10 total, it does not settle at a fixed level. Read the
75
+ * terrain's resulting vertical position (world Y — not the accumulated
76
+ * shift) back with {@link PluginCoreIoTerrainApi.getDatum}.
77
+ *
78
+ * @param offset - How far to shift the terrain down, in internal units
79
+ * (negative raises it).
80
+ * @throws if writes are disabled, there is no terrain, or the terrain is
81
+ * **locked** (unlock it in the app first).
82
+ *
83
+ * @examplePrompt Shift the terrain datum down by 12
84
+ * @examplePrompt Lower the site terrain by 10
85
+ * @examplePrompt Raise the terrain a little
86
+ * @examplePrompt Nudge the terrain datum down
87
+ *
88
+ * # Example
89
+ * ```ts
90
+ * await snaptrude.core.io.terrain.setDatum(12) // shift terrain down by 12 (relative)
91
+ * ```
92
+ */
93
+ public abstract setDatum(offset: number): PluginApiReturn<void>
94
+
95
+ /**
96
+ * Delete the site terrain. Undoable.
97
+ *
98
+ * @throws if writes are disabled, there is no terrain, or the terrain is
99
+ * **locked** (unlock it in the app first).
100
+ *
101
+ * @examplePrompt Delete the site terrain
102
+ * @examplePrompt Remove the topography
103
+ * @examplePrompt Clear the imported site
104
+ * @examplePrompt Get rid of the terrain
105
+ */
106
+ public abstract delete(): PluginApiReturn<void>
107
+
108
+ /**
109
+ * The terrain cut/fill earthwork report — cut, fill, and net volumes — or
110
+ * `null` if there is no terrain.
111
+ *
112
+ * @examplePrompt What are the cut and fill volumes for the site?
113
+ * @examplePrompt Get the terrain earthwork report
114
+ * @examplePrompt How much cut and fill does the grading need?
115
+ * @examplePrompt Show the net volume of the terrain edits
116
+ *
117
+ * # Example
118
+ * ```ts
119
+ * const r = await snaptrude.core.io.terrain.getReport()
120
+ * if (r) console.log(`cut ${r.cutVolume}, fill ${r.fillVolume}, net ${r.netVolume}`)
121
+ * ```
122
+ */
123
+ public abstract getReport(): PluginApiReturn<TerrainReport | null>
124
+
125
+ /** Whether terrain elevation (DEM height) is on. `null` if no terrain. */
126
+ public abstract isElevationEnabled(): PluginApiReturn<boolean | null>
127
+ /**
128
+ * Turn terrain elevation (DEM height) ON — a real 3D topography surface. Undoable.
129
+ * @throws if writes are disabled, there is no terrain, or the terrain is
130
+ * **locked** (unlock it in the app first).
131
+ * @examplePrompt Turn on terrain elevation
132
+ * @examplePrompt Enable the site heightmap
133
+ * @examplePrompt Make the terrain 3D
134
+ * @examplePrompt Show the topography relief
135
+ */
136
+ public abstract enableElevation(): PluginApiReturn<void>
137
+ /**
138
+ * Turn terrain elevation OFF — flatten to a plane. Undoable.
139
+ * @throws if writes are disabled, there is no terrain, or the terrain is
140
+ * **locked** (unlock it in the app first).
141
+ * @examplePrompt Flatten the terrain
142
+ * @examplePrompt Turn off site elevation
143
+ * @examplePrompt Disable the heightmap
144
+ * @examplePrompt Make the terrain flat
145
+ */
146
+ public abstract disableElevation(): PluginApiReturn<void>
147
+
148
+ /** Whether satellite imagery is draped on the terrain. `null` if no terrain. */
149
+ public abstract isSatelliteEnabled(): PluginApiReturn<boolean | null>
150
+ /**
151
+ * Turn satellite imagery ON. Undoable.
152
+ * @throws if writes are disabled, there is no terrain, or the terrain is
153
+ * **locked** (unlock it in the app first).
154
+ * @examplePrompt Show satellite imagery on the site
155
+ * @examplePrompt Enable the satellite texture
156
+ * @examplePrompt Turn on aerial imagery
157
+ * @examplePrompt Drape satellite over the terrain
158
+ */
159
+ public abstract enableSatellite(): PluginApiReturn<void>
160
+ /**
161
+ * Turn satellite imagery OFF. Undoable.
162
+ * @throws if writes are disabled, there is no terrain, or the terrain is
163
+ * **locked** (unlock it in the app first).
164
+ * @examplePrompt Hide the satellite imagery
165
+ * @examplePrompt Turn off the aerial texture
166
+ * @examplePrompt Disable satellite on the site
167
+ * @examplePrompt Remove the satellite drape
168
+ */
169
+ public abstract disableSatellite(): PluginApiReturn<void>
170
+
171
+ /**
172
+ * Replace the terrain surface with a caller-supplied triangle mesh. Undoable
173
+ * (one step), and the replacement persists with the project. The returned
174
+ * promise resolves only after the surface is fully applied and recorded —
175
+ * it is safe to toggle terrain resolution or read the surface back the
176
+ * moment it resolves.
177
+ *
178
+ * `positions` is a flat `[x, y, z, …]` array in **world space** — the same
179
+ * frame `design.query.geometry.getTriangulatedMeshes` reads — so a
180
+ * read-modify-write round trip needs no conversion. `indices` is a flat
181
+ * triangle list into `positions` (three indices per triangle). A
182
+ * predominantly down-facing surface is flipped automatically (reported in
183
+ * `warnings`), and zero-area sliver triangles are tolerated and counted.
184
+ *
185
+ * **What survives the replacement:** the datum, geolocation, opacity, lock
186
+ * state, and the elevation/satellite toggles. The map/satellite texture is
187
+ * re-projected onto the new surface from above (best effort — alignment is
188
+ * approximate, reported in `warnings`). **What resets:** cut/fill history
189
+ * and the earthwork report — the replaced surface starts with a clean
190
+ * grading slate.
191
+ *
192
+ * Limits: at most 500,000 triangles and 500,000 vertices; every coordinate
193
+ * must be finite and within the scene bound.
194
+ *
195
+ * @param positions - Flat `[x, y, z, …]` world-space vertex positions.
196
+ * @param indices - Flat triangle list into `positions`.
197
+ * @param units - `"world"` (default): coordinates are raw internal units;
198
+ * `"meters"`: coordinates are metres and are converted on the way in.
199
+ * @param options - Optional {@linkcode PluginTerrainReplaceMeshOptions}:
200
+ * optimistic-concurrency expectations (`expectedTerrain`,
201
+ * `expectedModelRevision`), `preserve` opt-outs, idempotent replay via
202
+ * `clientMutationId`, and the `coordinateSpace`/`baseline` declarations.
203
+ * @throws if writes are disabled, there is no terrain (import one first),
204
+ * the terrain is **locked**, the mesh fails validation (non-finite or
205
+ * out-of-bound coordinates, bad indices, degenerate-only geometry, over
206
+ * the size caps), `expectedTerrain` does not match the live terrain, or
207
+ * `expectedModelRevision` is stale.
208
+ *
209
+ * @examplePrompt Replace the terrain with this surveyed mesh
210
+ * @examplePrompt Flatten a building pad into the site surface
211
+ * @examplePrompt Load a custom DEM surface onto the terrain
212
+ * @examplePrompt Regrade the terrain from these points
213
+ *
214
+ * # Example
215
+ * ```ts
216
+ * // Projects with no terrain yet: import first, then replace.
217
+ * if (!(await snaptrude.core.io.terrain.exists())) {
218
+ * await snaptrude.core.io.import.terrain(40.7128, -74.006, 300, 300)
219
+ * }
220
+ * const result = await snaptrude.core.io.terrain.replaceMesh(
221
+ * positions, // [x0, y0, z0, x1, y1, z1, …] — world space
222
+ * indices, // [a0, b0, c0, a1, b1, c1, …]
223
+ * "meters",
224
+ * {
225
+ * coordinateSpace: "world",
226
+ * expectedTerrain: await snaptrude.core.io.terrain.get(),
227
+ * baseline: "make-replacement-original",
228
+ * preserve: { datum: true, geolocation: true, satellite: true, material: true },
229
+ * clientMutationId: "survey-2026-08-05-r1",
230
+ * },
231
+ * )
232
+ * // result.modelRevision — pass back as expectedModelRevision on the next call
233
+ * ```
234
+ */
235
+ public abstract replaceMesh(
236
+ positions: number[],
237
+ indices: number[],
238
+ units?: "world" | "meters",
239
+ options?: PluginTerrainReplaceMeshOptions,
240
+ ): PluginApiReturn<PluginTerrainReplaceMeshResult>
241
+
242
+ /** Read the terrain opacity, `0`..`1`, or `null` if no terrain. */
243
+ public abstract getOpacity(): PluginApiReturn<number | null>
244
+ /**
245
+ * Set the terrain opacity (`0` transparent .. `1` opaque). Undoable.
246
+ * @param opacity - Target opacity, `0`..`1`.
247
+ * @throws if writes are disabled, there is no terrain, or the terrain is
248
+ * **locked** (unlock it in the app first).
249
+ * @examplePrompt Fade the terrain to 50%
250
+ * @examplePrompt Make the site semi-transparent
251
+ * @examplePrompt Set terrain opacity to 0.3
252
+ * @examplePrompt Dim the topography
253
+ *
254
+ * # Example
255
+ * ```ts
256
+ * await snaptrude.core.io.terrain.setOpacity(0.5)
257
+ * ```
258
+ */
259
+ public abstract setOpacity(opacity: number): PluginApiReturn<void>
260
+ }
261
+
262
+ /**
263
+ * Terrain cut/fill earthwork report. Volumes are in the **project's display
264
+ * volume unit** (what the UI shows), not internal units.
265
+ *
266
+ * | Property | Type | Description |
267
+ * |---|---|---|
268
+ * | `cutVolume` | `number` | Total excavated (cut) volume |
269
+ * | `fillVolume` | `number` | Total added (fill) volume |
270
+ * | `netVolume` | `number` | Net volume (`fill − cut`) |
271
+ */
272
+ export const TerrainReport = z.object({
273
+ cutVolume: z.number(),
274
+ fillVolume: z.number(),
275
+ netVolume: z.number(),
276
+ })
277
+ export type TerrainReport = z.infer<typeof TerrainReport>
278
+
279
+ /**
280
+ * Result of {@link PluginCoreIoTerrainApi.replaceMesh}.
281
+ *
282
+ * | Property | Type | Description |
283
+ * |---|---|---|
284
+ * | `terrain` | `TerrainHandle` | The terrain (unchanged singleton handle) |
285
+ * | `modelRevision` | `number` | Session-scoped terrain-mesh revision after this replace — pass back as `expectedModelRevision` for compare-and-swap semantics |
286
+ * | `vertexCount` | `number` | Vertices in the applied mesh |
287
+ * | `triangleCount` | `number` | Triangles in the applied mesh |
288
+ * | `warnings` | `string[]` | Non-fatal notes: winding flipped, sliver triangles, approximate texture re-projection |
289
+ */
290
+ export type PluginTerrainReplaceMeshResult = {
291
+ terrain: TerrainHandle
292
+ modelRevision: number
293
+ vertexCount: number
294
+ triangleCount: number
295
+ warnings: string[]
296
+ }
297
+
298
+ /**
299
+ * Options for {@link PluginCoreIoTerrainApi.replaceMesh}.
300
+ *
301
+ * | Property | Type | Description |
302
+ * |---|---|---|
303
+ * | `coordinateSpace` | `"world"`? | Declares the input frame. `world` is the only supported space (the same frame `getTriangulatedMeshes` reads) |
304
+ * | `expectedTerrain` | `TerrainHandle`? | Optimistic check: throws `HANDLE_INVALID` if the live terrain is not this handle (session-scoped — handles do not survive reloads) |
305
+ * | `expectedModelRevision` | `number`? | Optimistic check against the session terrain-mesh revision (starts at `0`, increments per successful `replaceMesh`; the result returns the new value). Stale → `PRECONDITION_FAILED` with the current revision in `details` |
306
+ * | `baseline` | `"make-replacement-original"`? | Declares replacement semantics. This is the only (and default) behavior: the replacement becomes the persisted surface; the app's terrain Reset restores the original map heightmap as the escape hatch |
307
+ * | `preserve` | object? | Opt-outs, all defaulting `true`. `datum: false` resets the terrain transform (authored coordinates become the local frame). `satellite: false` switches the drape off after the replace. `material: false` skips texture re-projection — the whole surface takes the ground material. `geolocation: false` is rejected (`VALIDATION`): geolocation is always preserved in this version |
308
+ * | `clientMutationId` | `string`? | Session-scoped idempotency: a repeated call with the same id returns the original result without re-executing |
309
+ */
310
+ export const PluginTerrainReplaceMeshOptions = z
311
+ .object({
312
+ coordinateSpace: z.literal("world").optional(),
313
+ expectedTerrain: z.string().min(1).optional(),
314
+ expectedModelRevision: z.number().int().nonnegative().optional(),
315
+ baseline: z.literal("make-replacement-original").optional(),
316
+ preserve: z
317
+ .object({
318
+ datum: z.boolean().optional(),
319
+ geolocation: z.boolean().optional(),
320
+ satellite: z.boolean().optional(),
321
+ material: z.boolean().optional(),
322
+ })
323
+ .strict()
324
+ .optional(),
325
+ clientMutationId: z.string().min(1).max(128).optional(),
326
+ })
327
+ .strict()
328
+ export type PluginTerrainReplaceMeshOptions = z.infer<typeof PluginTerrainReplaceMeshOptions>
329
+
330
+ /**
331
+ * Arguments for {@link PluginCoreIoTerrainApi.replaceMesh}. The caps are the
332
+ * plugin surface's explicit payload ceiling: 500k vertices / 500k triangles.
333
+ */
334
+ export const PluginTerrainReplaceMeshArgs = z.object({
335
+ positions: z
336
+ .array(z.number().finite())
337
+ .min(9)
338
+ .max(1_500_000)
339
+ .refine((a) => a.length % 3 === 0, {
340
+ message: "positions must be a flat [x, y, z, …] array (length a multiple of 3)",
341
+ }),
342
+ indices: z
343
+ .array(z.number().int().nonnegative())
344
+ .min(3)
345
+ .max(1_500_000)
346
+ .refine((a) => a.length % 3 === 0, {
347
+ message: "indices must be a flat triangle list (length a multiple of 3)",
348
+ }),
349
+ units: z.enum(["world", "meters"]).optional(),
350
+ options: PluginTerrainReplaceMeshOptions.optional(),
351
+ })
352
+ export type PluginTerrainReplaceMeshArgs = z.infer<typeof PluginTerrainReplaceMeshArgs>
353
+
354
+ /** Arguments for {@link PluginCoreIoTerrainApi.setDatum}. */
355
+ export const PluginTerrainSetDatumArgs = z.object({ offset: z.number().finite() })
356
+ export type PluginTerrainSetDatumArgs = z.infer<typeof PluginTerrainSetDatumArgs>
357
+
358
+ /** Arguments for {@link PluginCoreIoTerrainApi.setOpacity}. */
359
+ export const PluginTerrainSetOpacityArgs = z.object({ opacity: z.number().min(0).max(1) })
360
+ export type PluginTerrainSetOpacityArgs = z.infer<typeof PluginTerrainSetOpacityArgs>