@snaptrude/plugin-core 0.9.16 → 0.9.18-networks-20261016.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 (215) hide show
  1. package/AGENTS.md +231 -231
  2. package/CHANGELOG.md +408 -402
  3. package/CLAUDE.md +11 -11
  4. package/dist/api/analysis/daylight.d.ts +5 -5
  5. package/dist/api/analysis/solar.d.ts +2 -2
  6. package/dist/api/core/camera/index.d.ts +29 -0
  7. package/dist/api/core/camera/index.d.ts.map +1 -1
  8. package/dist/api/core/geom/create/index.d.ts +7 -1
  9. package/dist/api/core/geom/create/index.d.ts.map +1 -1
  10. package/dist/api/core/geom/update/contour.d.ts +8 -2
  11. package/dist/api/core/geom/update/contour.d.ts.map +1 -1
  12. package/dist/api/core/zoom/index.d.ts +13 -0
  13. package/dist/api/core/zoom/index.d.ts.map +1 -1
  14. package/dist/api/design/bim.d.ts +209 -0
  15. package/dist/api/design/bim.d.ts.map +1 -0
  16. package/dist/api/design/boolean/index.d.ts +2 -0
  17. package/dist/api/design/boolean/index.d.ts.map +1 -1
  18. package/dist/api/design/catalog.d.ts +320 -0
  19. package/dist/api/design/catalog.d.ts.map +1 -0
  20. package/dist/api/design/create/bulk-items.d.ts +65 -25
  21. package/dist/api/design/create/bulk-items.d.ts.map +1 -1
  22. package/dist/api/design/create/index.d.ts +272 -99
  23. package/dist/api/design/create/index.d.ts.map +1 -1
  24. package/dist/api/design/create/opening-fields.d.ts +13 -12
  25. package/dist/api/design/create/opening-fields.d.ts.map +1 -1
  26. package/dist/api/design/delete/index.d.ts +1 -0
  27. package/dist/api/design/delete/index.d.ts.map +1 -1
  28. package/dist/api/design/doors/index.d.ts +18 -24
  29. package/dist/api/design/doors/index.d.ts.map +1 -1
  30. package/dist/api/design/family.d.ts +797 -27
  31. package/dist/api/design/family.d.ts.map +1 -1
  32. package/dist/api/design/index.d.ts +16 -0
  33. package/dist/api/design/index.d.ts.map +1 -1
  34. package/dist/api/design/networks.d.ts +1763 -0
  35. package/dist/api/design/networks.d.ts.map +1 -0
  36. package/dist/api/design/query/index.d.ts +42 -32
  37. package/dist/api/design/query/index.d.ts.map +1 -1
  38. package/dist/api/design/selection/index.d.ts +10 -10
  39. package/dist/api/design/types/index.d.ts +40 -24
  40. package/dist/api/design/types/index.d.ts.map +1 -1
  41. package/dist/api/design/update/index.d.ts +43 -3
  42. package/dist/api/design/update/index.d.ts.map +1 -1
  43. package/dist/api/design/windows/index.d.ts +8 -8
  44. package/dist/api/design/windows/index.d.ts.map +1 -1
  45. package/dist/api/presentation/aiInspiration.d.ts +10 -10
  46. package/dist/api/presentation/annotate.d.ts +38 -22
  47. package/dist/api/presentation/annotate.d.ts.map +1 -1
  48. package/dist/api/presentation/drawingContract.d.ts +32 -0
  49. package/dist/api/presentation/drawingContract.d.ts.map +1 -0
  50. package/dist/api/presentation/drawings.d.ts +3523 -0
  51. package/dist/api/presentation/drawings.d.ts.map +1 -0
  52. package/dist/api/presentation/export.d.ts +23 -5
  53. package/dist/api/presentation/export.d.ts.map +1 -1
  54. package/dist/api/presentation/index.d.ts +41 -12
  55. package/dist/api/presentation/index.d.ts.map +1 -1
  56. package/dist/api/presentation/placedViews.d.ts +106 -6
  57. package/dist/api/presentation/placedViews.d.ts.map +1 -1
  58. package/dist/api/presentation/sections.d.ts +461 -0
  59. package/dist/api/presentation/sections.d.ts.map +1 -0
  60. package/dist/api/presentation/shapes.d.ts +2 -2
  61. package/dist/api/presentation/sheets.d.ts +175 -19
  62. package/dist/api/presentation/sheets.d.ts.map +1 -1
  63. package/dist/api/presentation/viewPresets.d.ts +222 -0
  64. package/dist/api/presentation/viewPresets.d.ts.map +1 -0
  65. package/dist/api/presentation/views.d.ts +103 -5
  66. package/dist/api/presentation/views.d.ts.map +1 -1
  67. package/dist/api/presentation/walkthroughs.d.ts +6 -6
  68. package/dist/errors/codes.d.ts +3 -1
  69. package/dist/errors/codes.d.ts.map +1 -1
  70. package/dist/index.cjs +3788 -2328
  71. package/dist/index.cjs.map +1 -1
  72. package/dist/index.js +3650 -2328
  73. package/dist/index.js.map +1 -1
  74. package/package.json +42 -42
  75. package/scripts/check-dist-fresh.mjs +22 -22
  76. package/scripts/generate-manifest.mjs +243 -238
  77. package/scripts/generate-manifest.test.mjs +303 -303
  78. package/src/api/analysis/daylight.ts +470 -470
  79. package/src/api/analysis/heatmaps.ts +683 -683
  80. package/src/api/analysis/illuminance.ts +155 -155
  81. package/src/api/analysis/index.ts +61 -61
  82. package/src/api/analysis/shadows.ts +183 -183
  83. package/src/api/analysis/solar.ts +237 -237
  84. package/src/api/analysis/sunlightHours.ts +211 -211
  85. package/src/api/analysis/sunpath.ts +83 -83
  86. package/src/api/analysis/weather.ts +179 -179
  87. package/src/api/core/buildings.ts +485 -485
  88. package/src/api/core/camera/index.ts +696 -667
  89. package/src/api/core/comment/index.ts +376 -376
  90. package/src/api/core/geom/create/index.ts +2139 -2133
  91. package/src/api/core/geom/delete/index.ts +84 -84
  92. package/src/api/core/geom/index.ts +35 -35
  93. package/src/api/core/geom/query/arc.ts +169 -169
  94. package/src/api/core/geom/query/brep.ts +621 -621
  95. package/src/api/core/geom/query/circle.ts +404 -404
  96. package/src/api/core/geom/query/contour.ts +540 -540
  97. package/src/api/core/geom/query/curve.ts +1102 -1102
  98. package/src/api/core/geom/query/edge.ts +130 -130
  99. package/src/api/core/geom/query/face.ts +508 -508
  100. package/src/api/core/geom/query/halfedge.ts +210 -210
  101. package/src/api/core/geom/query/index.ts +63 -63
  102. package/src/api/core/geom/query/profile.ts +473 -473
  103. package/src/api/core/geom/query/vertex.ts +205 -205
  104. package/src/api/core/geom/update/contour.ts +323 -317
  105. package/src/api/core/geom/update/curve.ts +209 -209
  106. package/src/api/core/geom/update/index.ts +29 -29
  107. package/src/api/core/geom/update/profile.ts +379 -379
  108. package/src/api/core/groups.ts +521 -521
  109. package/src/api/core/handles/index.ts +234 -234
  110. package/src/api/core/history/index.ts +84 -84
  111. package/src/api/core/index.ts +99 -99
  112. package/src/api/core/io/export/index.ts +126 -126
  113. package/src/api/core/io/import/index.ts +504 -504
  114. package/src/api/core/io/index.ts +42 -42
  115. package/src/api/core/io/job/index.ts +140 -140
  116. package/src/api/core/io/query/index.ts +71 -71
  117. package/src/api/core/io/terrain/index.ts +360 -360
  118. package/src/api/core/io/underlay/index.ts +705 -705
  119. package/src/api/core/layers.ts +540 -540
  120. package/src/api/core/math/index.ts +20 -20
  121. package/src/api/core/math/quat.ts +172 -172
  122. package/src/api/core/math/vec3.ts +179 -179
  123. package/src/api/core/mode/index.ts +108 -108
  124. package/src/api/core/project/index.ts +479 -479
  125. package/src/api/core/proposals/index.ts +570 -570
  126. package/src/api/core/storeys/index.ts +308 -308
  127. package/src/api/core/storeys/layers.ts +339 -339
  128. package/src/api/core/tags.ts +911 -911
  129. package/src/api/core/units/index.ts +164 -164
  130. package/src/api/core/user.ts +46 -46
  131. package/src/api/core/zoom/index.ts +64 -51
  132. package/src/api/design/bim.ts +121 -0
  133. package/src/api/design/boolean/index.ts +181 -179
  134. package/src/api/design/catalog.ts +203 -0
  135. package/src/api/design/create/bulk-items.ts +294 -254
  136. package/src/api/design/create/grids.ts +137 -137
  137. package/src/api/design/create/index.ts +2148 -1980
  138. package/src/api/design/create/opening-fields.ts +40 -37
  139. package/src/api/design/delete/index.ts +75 -74
  140. package/src/api/design/dimensions.ts +453 -453
  141. package/src/api/design/doors/index.ts +516 -500
  142. package/src/api/design/edit/index.ts +54 -54
  143. package/src/api/design/erase/index.ts +151 -151
  144. package/src/api/design/family.ts +1334 -704
  145. package/src/api/design/furniture/index.ts +319 -319
  146. package/src/api/design/grids.ts +237 -237
  147. package/src/api/design/index.ts +304 -274
  148. package/src/api/design/lock.ts +69 -69
  149. package/src/api/design/materials/index.ts +608 -608
  150. package/src/api/design/networks.ts +667 -0
  151. package/src/api/design/query/geometry/index.ts +319 -319
  152. package/src/api/design/query/grids.ts +197 -197
  153. package/src/api/design/query/index.ts +1236 -1226
  154. package/src/api/design/query/referenceLines.ts +52 -52
  155. package/src/api/design/query/spaces.ts +275 -275
  156. package/src/api/design/selection/index.ts +273 -273
  157. package/src/api/design/shared.ts +40 -40
  158. package/src/api/design/transform/index.ts +254 -254
  159. package/src/api/design/types/index.ts +163 -156
  160. package/src/api/design/update/index.ts +1024 -983
  161. package/src/api/design/visibility.ts +143 -143
  162. package/src/api/design/windows/index.ts +351 -333
  163. package/src/api/entity/buildableEnvelope.ts +322 -322
  164. package/src/api/entity/index.ts +30 -30
  165. package/src/api/entity/referenceLine.ts +235 -235
  166. package/src/api/entity/space.ts +612 -612
  167. package/src/api/entity/story.ts +517 -517
  168. package/src/api/index.ts +47 -47
  169. package/src/api/presentation/aiInspiration.ts +1116 -1116
  170. package/src/api/presentation/annotate.ts +417 -385
  171. package/src/api/presentation/camera.ts +289 -289
  172. package/src/api/presentation/diagrams.ts +194 -194
  173. package/src/api/presentation/drawingContract.ts +70 -0
  174. package/src/api/presentation/drawings.ts +1179 -0
  175. package/src/api/presentation/export.ts +134 -108
  176. package/src/api/presentation/import.ts +159 -159
  177. package/src/api/presentation/index.ts +160 -126
  178. package/src/api/presentation/placedViews.ts +1211 -1120
  179. package/src/api/presentation/sections.ts +420 -0
  180. package/src/api/presentation/shapes.ts +274 -274
  181. package/src/api/presentation/sheets.ts +746 -585
  182. package/src/api/presentation/slideshow.ts +134 -134
  183. package/src/api/presentation/tables.ts +84 -84
  184. package/src/api/presentation/viewPresets.ts +241 -0
  185. package/src/api/presentation/views.ts +713 -673
  186. package/src/api/presentation/walkthroughs.ts +1201 -1201
  187. package/src/api/program/adjacency.ts +164 -164
  188. package/src/api/program/areas.ts +408 -408
  189. package/src/api/program/classification.ts +138 -138
  190. package/src/api/program/cores.ts +83 -83
  191. package/src/api/program/departments.ts +517 -517
  192. package/src/api/program/index.ts +73 -73
  193. package/src/api/program/labels.ts +332 -332
  194. package/src/api/program/layout.ts +422 -422
  195. package/src/api/program/metadata.ts +364 -364
  196. package/src/api/program/metrics.ts +120 -120
  197. package/src/api/program/site.ts +748 -748
  198. package/src/api/program/spreadsheet.ts +2698 -2698
  199. package/src/api/workspace/index.ts +612 -612
  200. package/src/errors/codes.ts +143 -136
  201. package/src/errors/envelope.ts +75 -75
  202. package/src/errors/index.ts +21 -21
  203. package/src/errors/plugin-error.ts +134 -134
  204. package/src/handles.ts +297 -297
  205. package/src/host-utils.ts +67 -67
  206. package/src/index.ts +7 -7
  207. package/src/massParameters.ops.ts +246 -246
  208. package/src/massParameters.ts +427 -427
  209. package/src/types.ts +16 -16
  210. package/test/drawingContract.test.mjs +288 -0
  211. package/test/errors.test.mjs +185 -184
  212. package/test/massParameters.test.mjs +952 -952
  213. package/tsconfig.json +22 -22
  214. package/tsup.config.ts +12 -12
  215. package/api-manifest.json +0 -9618
@@ -1,54 +1,54 @@
1
- import * as z from "zod"
2
- import { PluginApiReturn } from "../../../types"
3
- import { ComponentHandle, Vec3Handle } from "../../../handles"
4
- import { OffsetSplitOutcome } from "../shared"
5
-
6
- /**
7
- * STAGED (LLD Wave 2) — abstract shell only. NOT yet wired into `PluginDesignApi`
8
- * and has no host implementation. `offsetSplit` migrates off `tools.offset` (adding
9
- * the previously-dropped `offsetValue` to the result).
10
- *
11
- * `snaptrude.design.edit` — non-create geometry edits (offset-split, and later
12
- * push-pull / topology edits). Undoable.
13
- *
14
- * TRANSPORT: positional args per method.
15
- */
16
- export abstract class PluginDesignEditApi {
17
- constructor() {}
18
-
19
- /**
20
- * Offset the top profile of a component by a distance and split the face along
21
- * the offset curve. Positive distances offset outward, negative inward.
22
- * Single-component only (the engine rejects batches).
23
- * @param component - The component whose top profile is offset-split.
24
- * @param offsetDistance - Offset distance; positive = outward, negative = inward.
25
- * @param options - Optional settings: `profilePickPoint` picks the profile when ambiguous.
26
- * @returns {@linkcode OffsetSplitOutcome} `{ createdIds, deletedIds, offsetValue }`
27
- *
28
- * @examplePrompt Offset the top face of this mass inward by 2 metres and split it
29
- * @examplePrompt Create a 1m setback border on top of the selected mass
30
- * @examplePrompt Split the roof profile with a 500mm inward offset
31
- * @examplePrompt Offset-split the slab's top profile outward by 3 feet
32
- *
33
- * # Example
34
- * ```ts
35
- * // Offset the top profile inward by 2 units and split the face along it
36
- * const [mass] = await snaptrude.design.query.listMasses()
37
- * const { createdIds, offsetValue } = await snaptrude.design.edit.offsetSplit(mass, -2)
38
- * // offsetValue is the post-clamp distance the engine actually applied
39
- * ```
40
- */
41
- public abstract offsetSplit(
42
- component: ComponentHandle,
43
- offsetDistance: number,
44
- options?: { profilePickPoint?: Vec3Handle },
45
- ): PluginApiReturn<OffsetSplitOutcome>
46
- }
47
-
48
- // Positional target: offsetSplit(component, offsetDistance, options?)
49
- export const PluginDesignOffsetSplitArgs = z.object({
50
- component: ComponentHandle,
51
- offsetDistance: z.number(),
52
- profilePickPoint: Vec3Handle.optional(),
53
- })
54
- export type PluginDesignOffsetSplitArgs = z.infer<typeof PluginDesignOffsetSplitArgs>
1
+ import * as z from "zod"
2
+ import { PluginApiReturn } from "../../../types"
3
+ import { ComponentHandle, Vec3Handle } from "../../../handles"
4
+ import { OffsetSplitOutcome } from "../shared"
5
+
6
+ /**
7
+ * STAGED (LLD Wave 2) — abstract shell only. NOT yet wired into `PluginDesignApi`
8
+ * and has no host implementation. `offsetSplit` migrates off `tools.offset` (adding
9
+ * the previously-dropped `offsetValue` to the result).
10
+ *
11
+ * `snaptrude.design.edit` — non-create geometry edits (offset-split, and later
12
+ * push-pull / topology edits). Undoable.
13
+ *
14
+ * TRANSPORT: positional args per method.
15
+ */
16
+ export abstract class PluginDesignEditApi {
17
+ constructor() {}
18
+
19
+ /**
20
+ * Offset the top profile of a component by a distance and split the face along
21
+ * the offset curve. Positive distances offset outward, negative inward.
22
+ * Single-component only (the engine rejects batches).
23
+ * @param component - The component whose top profile is offset-split.
24
+ * @param offsetDistance - Offset distance; positive = outward, negative = inward.
25
+ * @param options - Optional settings: `profilePickPoint` picks the profile when ambiguous.
26
+ * @returns {@linkcode OffsetSplitOutcome} `{ createdIds, deletedIds, offsetValue }`
27
+ *
28
+ * @examplePrompt Offset the top face of this mass inward by 2 metres and split it
29
+ * @examplePrompt Create a 1m setback border on top of the selected mass
30
+ * @examplePrompt Split the roof profile with a 500mm inward offset
31
+ * @examplePrompt Offset-split the slab's top profile outward by 3 feet
32
+ *
33
+ * # Example
34
+ * ```ts
35
+ * // Offset the top profile inward by 2 units and split the face along it
36
+ * const [mass] = await snaptrude.design.query.listMasses()
37
+ * const { createdIds, offsetValue } = await snaptrude.design.edit.offsetSplit(mass, -2)
38
+ * // offsetValue is the post-clamp distance the engine actually applied
39
+ * ```
40
+ */
41
+ public abstract offsetSplit(
42
+ component: ComponentHandle,
43
+ offsetDistance: number,
44
+ options?: { profilePickPoint?: Vec3Handle },
45
+ ): PluginApiReturn<OffsetSplitOutcome>
46
+ }
47
+
48
+ // Positional target: offsetSplit(component, offsetDistance, options?)
49
+ export const PluginDesignOffsetSplitArgs = z.object({
50
+ component: ComponentHandle,
51
+ offsetDistance: z.number(),
52
+ profilePickPoint: Vec3Handle.optional(),
53
+ })
54
+ export type PluginDesignOffsetSplitArgs = z.infer<typeof PluginDesignOffsetSplitArgs>
@@ -1,151 +1,151 @@
1
- import * as z from "zod"
2
- import { PluginApiReturn } from "../../../types"
3
- import { ComponentHandle, Vec3Handle } from "../../../handles"
4
-
5
- /**
6
- * The erase strategies exposed to plugins. `SplitAndUnion` is *enumerable* but
7
- * NOT committable via {@linkcode PluginDesignEraseApi.edge} (it needs an
8
- * interactive screen-space re-pick); `SplitAndDelete` is reserved in the engine
9
- * and intentionally omitted. Derived host-side by the engine's `decideStrategy`.
10
- */
11
- export const EraseStrategy = z.enum(["DirectDelete", "DirectUnion", "SplitAndUnion"])
12
- export type EraseStrategy = z.infer<typeof EraseStrategy>
13
-
14
- /** Default enumerated strategies — the two the scripted `edge()` can commit. */
15
- export const DEFAULT_ERASE_STRATEGIES: readonly EraseStrategy[] = ["DirectDelete", "DirectUnion"]
16
-
17
- /**
18
- * A **transient** reference to one erasable edge in the current plan's
19
- * bottom-adjacency graph.
20
- *
21
- * ⚠️ **Lifetime**: valid ONLY until the next geometry-modifying operation. Any
22
- * mutation (erase, boolean, transform, create, delete, …) rebuilds the adjacency
23
- * graph and invalidates every previously-returned ref. Passing a stale ref to
24
- * {@linkcode PluginDesignEraseApi.edge} throws `NO_STRATEGY_FOR_PICK_INFO`.
25
- * Always re-list after a mutation.
26
- *
27
- * This is a by-value record (round-trip it back to `edge()` unmodified), NOT a
28
- * registry handle. `components` and `snapPoint` are the marshalled public forms
29
- * of the engine's raw `mesh.uniqueId` numbers / by-value point.
30
- */
31
- export const ErasableEdgeRef = z.object({
32
- /** Opaque bottom-graph edge id (engine form `"e-<n>"`). Do not mutate. Pass verbatim to {@linkcode PluginDesignEraseApi.edge}. */
33
- id: z.string().min(1),
34
- /** What erasing this edge would do: `DirectDelete` drops a mass; `DirectUnion` merges two adjacent masses. */
35
- strategy: EraseStrategy,
36
- /** Bottom-graph edge weight: `1` = external boundary edge, `>=2` = internal edge shared between components. */
37
- edgeWeight: z.number(),
38
- /** The components this edge is incident to — one for external (DirectDelete); two or more for internal (DirectUnion; 3+ at T-junctions where several masses share the edge). */
39
- components: z.array(ComponentHandle),
40
- /** A representative point on the edge (its head endpoint). Diagnostic only. */
41
- snapPoint: Vec3Handle,
42
- })
43
- export type ErasableEdgeRef = z.infer<typeof ErasableEdgeRef>
44
-
45
- /**
46
- * Options for {@linkcode PluginDesignEraseApi.listErasableEdges}.
47
- *
48
- * | Property | Type | Description |
49
- * |---|---|---|
50
- * | `components` | {@linkcode ComponentHandle}`[]?` | Restrict to edges adjacent to at least one of these entities |
51
- * | `strategies` | {@linkcode EraseStrategy}`[]?` | Restrict to these strategies. Default `["DirectDelete","DirectUnion"]` (hides interactive-only `SplitAndUnion`) |
52
- *
53
- * TRANSPORT: positional now — `listErasableEdges(options?)`; this schema is
54
- * retained for host-side validation.
55
- */
56
- export const PluginDesignListErasableEdgesArgs = z.object({
57
- components: z.array(ComponentHandle).optional(),
58
- strategies: z.array(EraseStrategy).optional(),
59
- })
60
- export type PluginDesignListErasableEdgesArgs = z.infer<typeof PluginDesignListErasableEdgesArgs>
61
-
62
- /**
63
- * Arguments for {@linkcode PluginDesignEraseApi.edge}.
64
- *
65
- * TRANSPORT: positional now — `edge(edge: ErasableEdgeRef)`; this schema is
66
- * retained for host-side validation.
67
- */
68
- export const PluginDesignEraseEdgeArgs = z.object({
69
- edge: ErasableEdgeRef,
70
- })
71
- export type PluginDesignEraseEdgeArgs = z.infer<typeof PluginDesignEraseEdgeArgs>
72
-
73
- /** Result of {@linkcode PluginDesignEraseApi.edge} — success sentinel; the engine yields no survivor id. */
74
- export const PluginDesignEraseEdgeResult = z.object({ ok: z.literal(true) })
75
- export type PluginDesignEraseEdgeResult = z.infer<typeof PluginDesignEraseEdgeResult>
76
-
77
- /**
78
- * `snaptrude.design.erase` — **adjacency-edge erase** (plan-level topology op).
79
- *
80
- * Erase is NOT delete. The erase tool operates on an **edge**, and the effect is
81
- * derived from that edge: erasing an internal edge between two masses **unions**
82
- * them (`DirectUnion`); erasing an external boundary edge of a single mass
83
- * **drops** it behind the edge (`DirectDelete`). For hard entity removal use
84
- * `design.delete.entities`; for CSG geometry delete use `design.boolean.subtract`.
85
- *
86
- * Two-step: {@linkcode listErasableEdges} to enumerate, then {@linkcode edge} to
87
- * commit one ref (single undo entry). Scoped to **2D plan adjacency edges** in v1.
88
- *
89
- * TRANSPORT: positional args per method.
90
- */
91
- export abstract class PluginDesignEraseApi {
92
- constructor() {}
93
-
94
- /**
95
- * Enumerate every erasable edge in the current plan's bottom-adjacency graph
96
- * (one {@linkcode ErasableEdgeRef} per edge). Pure read — no scene mutation, no
97
- * command, not undoable. Erase-ineligible components (locked, hidden, off-storey)
98
- * are filtered out.
99
- *
100
- * ⚠️ Returned refs are **transient** — see {@linkcode ErasableEdgeRef}. Re-list
101
- * after any geometry mutation.
102
- *
103
- * @param options - {@linkcode PluginDesignListErasableEdgesArgs} — optional filters (`components`, `strategies`)
104
- * @returns The erasable edges (`[]` when none) — never `null`.
105
- *
106
- * @examplePrompt Which edges in my floor plan can be erased?
107
- * @examplePrompt List the erasable edges on this storey
108
- * @examplePrompt Show me the shared edges I could erase to merge rooms
109
- * @examplePrompt What edges between these two spaces can be removed?
110
- *
111
- * # Example
112
- * ```ts
113
- * const edges = await snaptrude.design.erase.listErasableEdges()
114
- * const union = edges.find((e) => e.strategy === "DirectUnion")
115
- * if (union) await snaptrude.design.erase.edge(union)
116
- * ```
117
- */
118
- public abstract listErasableEdges(
119
- options?: PluginDesignListErasableEdgesArgs,
120
- ): PluginApiReturn<ErasableEdgeRef[]>
121
-
122
- /**
123
- * Commit the erase for one edge. `DirectUnion` merges the two adjacent masses;
124
- * `DirectDelete` drops the single mass behind the boundary edge. Single undo entry.
125
- *
126
- * Pass an {@linkcode ErasableEdgeRef} from {@linkcode listErasableEdges}
127
- * unmodified. A stale ref (graph rebuilt by a prior mutation) or a `SplitAndUnion`
128
- * edge throws.
129
- *
130
- * @param edge - The {@linkcode ErasableEdgeRef} to erase, from {@linkcode listErasableEdges} unmodified
131
- * @returns `{ ok: true }` on success (the engine yields no survivor id today).
132
- * @throws when the ref is stale, its components are all erase-ineligible, or the
133
- * strategy is not committable via the scripted path.
134
- *
135
- * @examplePrompt Erase the edge between these two rooms so they merge
136
- * @examplePrompt Remove the shared boundary between the kitchen and the dining space
137
- * @examplePrompt Merge the two adjacent rooms by erasing their common edge
138
- * @examplePrompt Knock through the partition line between these spaces
139
- * @examplePrompt Erase this boundary edge from the plan
140
- *
141
- * # Example
142
- * ```ts
143
- * // Merge two adjacent rooms by erasing an internal edge they share
144
- * const edges = await snaptrude.design.erase.listErasableEdges({ strategies: ["DirectUnion"] })
145
- * if (edges.length > 0) {
146
- * const { ok } = await snaptrude.design.erase.edge(edges[0])
147
- * }
148
- * ```
149
- */
150
- public abstract edge(edge: ErasableEdgeRef): PluginApiReturn<PluginDesignEraseEdgeResult>
151
- }
1
+ import * as z from "zod"
2
+ import { PluginApiReturn } from "../../../types"
3
+ import { ComponentHandle, Vec3Handle } from "../../../handles"
4
+
5
+ /**
6
+ * The erase strategies exposed to plugins. `SplitAndUnion` is *enumerable* but
7
+ * NOT committable via {@linkcode PluginDesignEraseApi.edge} (it needs an
8
+ * interactive screen-space re-pick); `SplitAndDelete` is reserved in the engine
9
+ * and intentionally omitted. Derived host-side by the engine's `decideStrategy`.
10
+ */
11
+ export const EraseStrategy = z.enum(["DirectDelete", "DirectUnion", "SplitAndUnion"])
12
+ export type EraseStrategy = z.infer<typeof EraseStrategy>
13
+
14
+ /** Default enumerated strategies — the two the scripted `edge()` can commit. */
15
+ export const DEFAULT_ERASE_STRATEGIES: readonly EraseStrategy[] = ["DirectDelete", "DirectUnion"]
16
+
17
+ /**
18
+ * A **transient** reference to one erasable edge in the current plan's
19
+ * bottom-adjacency graph.
20
+ *
21
+ * ⚠️ **Lifetime**: valid ONLY until the next geometry-modifying operation. Any
22
+ * mutation (erase, boolean, transform, create, delete, …) rebuilds the adjacency
23
+ * graph and invalidates every previously-returned ref. Passing a stale ref to
24
+ * {@linkcode PluginDesignEraseApi.edge} throws `NO_STRATEGY_FOR_PICK_INFO`.
25
+ * Always re-list after a mutation.
26
+ *
27
+ * This is a by-value record (round-trip it back to `edge()` unmodified), NOT a
28
+ * registry handle. `components` and `snapPoint` are the marshalled public forms
29
+ * of the engine's raw `mesh.uniqueId` numbers / by-value point.
30
+ */
31
+ export const ErasableEdgeRef = z.object({
32
+ /** Opaque bottom-graph edge id (engine form `"e-<n>"`). Do not mutate. Pass verbatim to {@linkcode PluginDesignEraseApi.edge}. */
33
+ id: z.string().min(1),
34
+ /** What erasing this edge would do: `DirectDelete` drops a mass; `DirectUnion` merges two adjacent masses. */
35
+ strategy: EraseStrategy,
36
+ /** Bottom-graph edge weight: `1` = external boundary edge, `>=2` = internal edge shared between components. */
37
+ edgeWeight: z.number(),
38
+ /** The components this edge is incident to — one for external (DirectDelete); two or more for internal (DirectUnion; 3+ at T-junctions where several masses share the edge). */
39
+ components: z.array(ComponentHandle),
40
+ /** A representative point on the edge (its head endpoint). Diagnostic only. */
41
+ snapPoint: Vec3Handle,
42
+ })
43
+ export type ErasableEdgeRef = z.infer<typeof ErasableEdgeRef>
44
+
45
+ /**
46
+ * Options for {@linkcode PluginDesignEraseApi.listErasableEdges}.
47
+ *
48
+ * | Property | Type | Description |
49
+ * |---|---|---|
50
+ * | `components` | {@linkcode ComponentHandle}`[]?` | Restrict to edges adjacent to at least one of these entities |
51
+ * | `strategies` | {@linkcode EraseStrategy}`[]?` | Restrict to these strategies. Default `["DirectDelete","DirectUnion"]` (hides interactive-only `SplitAndUnion`) |
52
+ *
53
+ * TRANSPORT: positional now — `listErasableEdges(options?)`; this schema is
54
+ * retained for host-side validation.
55
+ */
56
+ export const PluginDesignListErasableEdgesArgs = z.object({
57
+ components: z.array(ComponentHandle).optional(),
58
+ strategies: z.array(EraseStrategy).optional(),
59
+ })
60
+ export type PluginDesignListErasableEdgesArgs = z.infer<typeof PluginDesignListErasableEdgesArgs>
61
+
62
+ /**
63
+ * Arguments for {@linkcode PluginDesignEraseApi.edge}.
64
+ *
65
+ * TRANSPORT: positional now — `edge(edge: ErasableEdgeRef)`; this schema is
66
+ * retained for host-side validation.
67
+ */
68
+ export const PluginDesignEraseEdgeArgs = z.object({
69
+ edge: ErasableEdgeRef,
70
+ })
71
+ export type PluginDesignEraseEdgeArgs = z.infer<typeof PluginDesignEraseEdgeArgs>
72
+
73
+ /** Result of {@linkcode PluginDesignEraseApi.edge} — success sentinel; the engine yields no survivor id. */
74
+ export const PluginDesignEraseEdgeResult = z.object({ ok: z.literal(true) })
75
+ export type PluginDesignEraseEdgeResult = z.infer<typeof PluginDesignEraseEdgeResult>
76
+
77
+ /**
78
+ * `snaptrude.design.erase` — **adjacency-edge erase** (plan-level topology op).
79
+ *
80
+ * Erase is NOT delete. The erase tool operates on an **edge**, and the effect is
81
+ * derived from that edge: erasing an internal edge between two masses **unions**
82
+ * them (`DirectUnion`); erasing an external boundary edge of a single mass
83
+ * **drops** it behind the edge (`DirectDelete`). For hard entity removal use
84
+ * `design.delete.entities`; for CSG geometry delete use `design.boolean.subtract`.
85
+ *
86
+ * Two-step: {@linkcode listErasableEdges} to enumerate, then {@linkcode edge} to
87
+ * commit one ref (single undo entry). Scoped to **2D plan adjacency edges** in v1.
88
+ *
89
+ * TRANSPORT: positional args per method.
90
+ */
91
+ export abstract class PluginDesignEraseApi {
92
+ constructor() {}
93
+
94
+ /**
95
+ * Enumerate every erasable edge in the current plan's bottom-adjacency graph
96
+ * (one {@linkcode ErasableEdgeRef} per edge). Pure read — no scene mutation, no
97
+ * command, not undoable. Erase-ineligible components (locked, hidden, off-storey)
98
+ * are filtered out.
99
+ *
100
+ * ⚠️ Returned refs are **transient** — see {@linkcode ErasableEdgeRef}. Re-list
101
+ * after any geometry mutation.
102
+ *
103
+ * @param options - {@linkcode PluginDesignListErasableEdgesArgs} — optional filters (`components`, `strategies`)
104
+ * @returns The erasable edges (`[]` when none) — never `null`.
105
+ *
106
+ * @examplePrompt Which edges in my floor plan can be erased?
107
+ * @examplePrompt List the erasable edges on this storey
108
+ * @examplePrompt Show me the shared edges I could erase to merge rooms
109
+ * @examplePrompt What edges between these two spaces can be removed?
110
+ *
111
+ * # Example
112
+ * ```ts
113
+ * const edges = await snaptrude.design.erase.listErasableEdges()
114
+ * const union = edges.find((e) => e.strategy === "DirectUnion")
115
+ * if (union) await snaptrude.design.erase.edge(union)
116
+ * ```
117
+ */
118
+ public abstract listErasableEdges(
119
+ options?: PluginDesignListErasableEdgesArgs,
120
+ ): PluginApiReturn<ErasableEdgeRef[]>
121
+
122
+ /**
123
+ * Commit the erase for one edge. `DirectUnion` merges the two adjacent masses;
124
+ * `DirectDelete` drops the single mass behind the boundary edge. Single undo entry.
125
+ *
126
+ * Pass an {@linkcode ErasableEdgeRef} from {@linkcode listErasableEdges}
127
+ * unmodified. A stale ref (graph rebuilt by a prior mutation) or a `SplitAndUnion`
128
+ * edge throws.
129
+ *
130
+ * @param edge - The {@linkcode ErasableEdgeRef} to erase, from {@linkcode listErasableEdges} unmodified
131
+ * @returns `{ ok: true }` on success (the engine yields no survivor id today).
132
+ * @throws when the ref is stale, its components are all erase-ineligible, or the
133
+ * strategy is not committable via the scripted path.
134
+ *
135
+ * @examplePrompt Erase the edge between these two rooms so they merge
136
+ * @examplePrompt Remove the shared boundary between the kitchen and the dining space
137
+ * @examplePrompt Merge the two adjacent rooms by erasing their common edge
138
+ * @examplePrompt Knock through the partition line between these spaces
139
+ * @examplePrompt Erase this boundary edge from the plan
140
+ *
141
+ * # Example
142
+ * ```ts
143
+ * // Merge two adjacent rooms by erasing an internal edge they share
144
+ * const edges = await snaptrude.design.erase.listErasableEdges({ strategies: ["DirectUnion"] })
145
+ * if (edges.length > 0) {
146
+ * const { ok } = await snaptrude.design.erase.edge(edges[0])
147
+ * }
148
+ * ```
149
+ */
150
+ public abstract edge(edge: ErasableEdgeRef): PluginApiReturn<PluginDesignEraseEdgeResult>
151
+ }