@snaptrude/plugin-core 0.9.17 → 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 (213) hide show
  1. package/AGENTS.md +231 -231
  2. package/CHANGELOG.md +408 -408
  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 +32 -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/shapes.d.ts +2 -2
  59. package/dist/api/presentation/sheets.d.ts +175 -19
  60. package/dist/api/presentation/sheets.d.ts.map +1 -1
  61. package/dist/api/presentation/viewPresets.d.ts +222 -0
  62. package/dist/api/presentation/viewPresets.d.ts.map +1 -0
  63. package/dist/api/presentation/views.d.ts +103 -5
  64. package/dist/api/presentation/views.d.ts.map +1 -1
  65. package/dist/api/presentation/walkthroughs.d.ts +6 -6
  66. package/dist/errors/codes.d.ts +3 -1
  67. package/dist/errors/codes.d.ts.map +1 -1
  68. package/dist/index.cjs +3732 -2383
  69. package/dist/index.cjs.map +1 -1
  70. package/dist/index.js +3607 -2383
  71. package/dist/index.js.map +1 -1
  72. package/package.json +42 -42
  73. package/scripts/check-dist-fresh.mjs +22 -22
  74. package/scripts/generate-manifest.mjs +243 -238
  75. package/scripts/generate-manifest.test.mjs +303 -303
  76. package/src/api/analysis/daylight.ts +470 -470
  77. package/src/api/analysis/heatmaps.ts +683 -683
  78. package/src/api/analysis/illuminance.ts +155 -155
  79. package/src/api/analysis/index.ts +61 -61
  80. package/src/api/analysis/shadows.ts +183 -183
  81. package/src/api/analysis/solar.ts +237 -237
  82. package/src/api/analysis/sunlightHours.ts +211 -211
  83. package/src/api/analysis/sunpath.ts +83 -83
  84. package/src/api/analysis/weather.ts +179 -179
  85. package/src/api/core/buildings.ts +485 -485
  86. package/src/api/core/camera/index.ts +696 -667
  87. package/src/api/core/comment/index.ts +376 -376
  88. package/src/api/core/geom/create/index.ts +2139 -2133
  89. package/src/api/core/geom/delete/index.ts +84 -84
  90. package/src/api/core/geom/index.ts +35 -35
  91. package/src/api/core/geom/query/arc.ts +169 -169
  92. package/src/api/core/geom/query/brep.ts +621 -621
  93. package/src/api/core/geom/query/circle.ts +404 -404
  94. package/src/api/core/geom/query/contour.ts +540 -540
  95. package/src/api/core/geom/query/curve.ts +1102 -1102
  96. package/src/api/core/geom/query/edge.ts +130 -130
  97. package/src/api/core/geom/query/face.ts +508 -508
  98. package/src/api/core/geom/query/halfedge.ts +210 -210
  99. package/src/api/core/geom/query/index.ts +63 -63
  100. package/src/api/core/geom/query/profile.ts +473 -473
  101. package/src/api/core/geom/query/vertex.ts +205 -205
  102. package/src/api/core/geom/update/contour.ts +323 -317
  103. package/src/api/core/geom/update/curve.ts +209 -209
  104. package/src/api/core/geom/update/index.ts +29 -29
  105. package/src/api/core/geom/update/profile.ts +379 -379
  106. package/src/api/core/groups.ts +521 -521
  107. package/src/api/core/handles/index.ts +234 -234
  108. package/src/api/core/history/index.ts +84 -84
  109. package/src/api/core/index.ts +99 -99
  110. package/src/api/core/io/export/index.ts +126 -126
  111. package/src/api/core/io/import/index.ts +504 -504
  112. package/src/api/core/io/index.ts +42 -42
  113. package/src/api/core/io/job/index.ts +140 -140
  114. package/src/api/core/io/query/index.ts +71 -71
  115. package/src/api/core/io/terrain/index.ts +360 -360
  116. package/src/api/core/io/underlay/index.ts +705 -705
  117. package/src/api/core/layers.ts +540 -540
  118. package/src/api/core/math/index.ts +20 -20
  119. package/src/api/core/math/quat.ts +172 -172
  120. package/src/api/core/math/vec3.ts +179 -179
  121. package/src/api/core/mode/index.ts +108 -108
  122. package/src/api/core/project/index.ts +479 -479
  123. package/src/api/core/proposals/index.ts +570 -570
  124. package/src/api/core/storeys/index.ts +308 -308
  125. package/src/api/core/storeys/layers.ts +339 -339
  126. package/src/api/core/tags.ts +911 -911
  127. package/src/api/core/units/index.ts +164 -164
  128. package/src/api/core/user.ts +46 -46
  129. package/src/api/core/zoom/index.ts +64 -51
  130. package/src/api/design/bim.ts +121 -0
  131. package/src/api/design/boolean/index.ts +181 -179
  132. package/src/api/design/catalog.ts +203 -0
  133. package/src/api/design/create/bulk-items.ts +294 -254
  134. package/src/api/design/create/grids.ts +137 -137
  135. package/src/api/design/create/index.ts +2148 -1980
  136. package/src/api/design/create/opening-fields.ts +40 -37
  137. package/src/api/design/delete/index.ts +75 -74
  138. package/src/api/design/dimensions.ts +453 -453
  139. package/src/api/design/doors/index.ts +516 -500
  140. package/src/api/design/edit/index.ts +54 -54
  141. package/src/api/design/erase/index.ts +151 -151
  142. package/src/api/design/family.ts +1334 -704
  143. package/src/api/design/furniture/index.ts +319 -319
  144. package/src/api/design/grids.ts +237 -237
  145. package/src/api/design/index.ts +304 -274
  146. package/src/api/design/lock.ts +69 -69
  147. package/src/api/design/materials/index.ts +608 -608
  148. package/src/api/design/networks.ts +667 -0
  149. package/src/api/design/query/geometry/index.ts +319 -319
  150. package/src/api/design/query/grids.ts +197 -197
  151. package/src/api/design/query/index.ts +1236 -1226
  152. package/src/api/design/query/referenceLines.ts +52 -52
  153. package/src/api/design/query/spaces.ts +275 -275
  154. package/src/api/design/selection/index.ts +273 -273
  155. package/src/api/design/shared.ts +40 -40
  156. package/src/api/design/transform/index.ts +254 -254
  157. package/src/api/design/types/index.ts +163 -156
  158. package/src/api/design/update/index.ts +1024 -983
  159. package/src/api/design/visibility.ts +143 -143
  160. package/src/api/design/windows/index.ts +351 -333
  161. package/src/api/entity/buildableEnvelope.ts +322 -322
  162. package/src/api/entity/index.ts +30 -30
  163. package/src/api/entity/referenceLine.ts +235 -235
  164. package/src/api/entity/space.ts +612 -612
  165. package/src/api/entity/story.ts +517 -517
  166. package/src/api/index.ts +47 -47
  167. package/src/api/presentation/aiInspiration.ts +1116 -1116
  168. package/src/api/presentation/annotate.ts +417 -385
  169. package/src/api/presentation/camera.ts +289 -289
  170. package/src/api/presentation/diagrams.ts +194 -194
  171. package/src/api/presentation/drawingContract.ts +70 -0
  172. package/src/api/presentation/drawings.ts +1179 -0
  173. package/src/api/presentation/export.ts +134 -108
  174. package/src/api/presentation/import.ts +159 -159
  175. package/src/api/presentation/index.ts +160 -135
  176. package/src/api/presentation/placedViews.ts +1211 -1120
  177. package/src/api/presentation/sections.ts +420 -420
  178. package/src/api/presentation/shapes.ts +274 -274
  179. package/src/api/presentation/sheets.ts +746 -585
  180. package/src/api/presentation/slideshow.ts +134 -134
  181. package/src/api/presentation/tables.ts +84 -84
  182. package/src/api/presentation/viewPresets.ts +241 -0
  183. package/src/api/presentation/views.ts +713 -673
  184. package/src/api/presentation/walkthroughs.ts +1201 -1201
  185. package/src/api/program/adjacency.ts +164 -164
  186. package/src/api/program/areas.ts +408 -408
  187. package/src/api/program/classification.ts +138 -138
  188. package/src/api/program/cores.ts +83 -83
  189. package/src/api/program/departments.ts +517 -517
  190. package/src/api/program/index.ts +73 -73
  191. package/src/api/program/labels.ts +332 -332
  192. package/src/api/program/layout.ts +422 -422
  193. package/src/api/program/metadata.ts +364 -364
  194. package/src/api/program/metrics.ts +120 -120
  195. package/src/api/program/site.ts +748 -748
  196. package/src/api/program/spreadsheet.ts +2698 -2698
  197. package/src/api/workspace/index.ts +612 -612
  198. package/src/errors/codes.ts +143 -136
  199. package/src/errors/envelope.ts +75 -75
  200. package/src/errors/index.ts +21 -21
  201. package/src/errors/plugin-error.ts +134 -134
  202. package/src/handles.ts +297 -297
  203. package/src/host-utils.ts +67 -67
  204. package/src/index.ts +7 -7
  205. package/src/massParameters.ops.ts +246 -246
  206. package/src/massParameters.ts +427 -427
  207. package/src/types.ts +16 -16
  208. package/test/drawingContract.test.mjs +288 -0
  209. package/test/errors.test.mjs +185 -184
  210. package/test/massParameters.test.mjs +952 -952
  211. package/tsconfig.json +22 -22
  212. package/tsup.config.ts +12 -12
  213. package/api-manifest.json +0 -9711
@@ -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
+ }