@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,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
+ }