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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (221) hide show
  1. package/AGENTS.md +231 -231
  2. package/CHANGELOG.md +408 -402
  3. package/CLAUDE.md +11 -11
  4. package/api-manifest.json +1510 -701
  5. package/dist/api/analysis/daylight.d.ts +5 -5
  6. package/dist/api/analysis/solar.d.ts +2 -2
  7. package/dist/api/core/camera/index.d.ts +29 -0
  8. package/dist/api/core/camera/index.d.ts.map +1 -1
  9. package/dist/api/core/geom/create/index.d.ts +7 -1
  10. package/dist/api/core/geom/create/index.d.ts.map +1 -1
  11. package/dist/api/core/geom/update/contour.d.ts +8 -2
  12. package/dist/api/core/geom/update/contour.d.ts.map +1 -1
  13. package/dist/api/core/storeys/index.d.ts +5 -2
  14. package/dist/api/core/storeys/index.d.ts.map +1 -1
  15. package/dist/api/core/zoom/index.d.ts +13 -0
  16. package/dist/api/core/zoom/index.d.ts.map +1 -1
  17. package/dist/api/design/bim.d.ts +299 -0
  18. package/dist/api/design/bim.d.ts.map +1 -0
  19. package/dist/api/design/boolean/index.d.ts +2 -0
  20. package/dist/api/design/boolean/index.d.ts.map +1 -1
  21. package/dist/api/design/catalog.d.ts +320 -0
  22. package/dist/api/design/catalog.d.ts.map +1 -0
  23. package/dist/api/design/create/bulk-items.d.ts +65 -25
  24. package/dist/api/design/create/bulk-items.d.ts.map +1 -1
  25. package/dist/api/design/create/index.d.ts +299 -100
  26. package/dist/api/design/create/index.d.ts.map +1 -1
  27. package/dist/api/design/create/opening-fields.d.ts +13 -12
  28. package/dist/api/design/create/opening-fields.d.ts.map +1 -1
  29. package/dist/api/design/delete/index.d.ts +1 -0
  30. package/dist/api/design/delete/index.d.ts.map +1 -1
  31. package/dist/api/design/doors/index.d.ts +18 -24
  32. package/dist/api/design/doors/index.d.ts.map +1 -1
  33. package/dist/api/design/family.d.ts +813 -35
  34. package/dist/api/design/family.d.ts.map +1 -1
  35. package/dist/api/design/index.d.ts +16 -0
  36. package/dist/api/design/index.d.ts.map +1 -1
  37. package/dist/api/design/networks.d.ts +1703 -0
  38. package/dist/api/design/networks.d.ts.map +1 -0
  39. package/dist/api/design/query/grids.d.ts +2 -2
  40. package/dist/api/design/query/index.d.ts +42 -32
  41. package/dist/api/design/query/index.d.ts.map +1 -1
  42. package/dist/api/design/selection/index.d.ts +10 -10
  43. package/dist/api/design/types/index.d.ts +40 -24
  44. package/dist/api/design/types/index.d.ts.map +1 -1
  45. package/dist/api/design/update/index.d.ts +111 -6
  46. package/dist/api/design/update/index.d.ts.map +1 -1
  47. package/dist/api/design/windows/index.d.ts +8 -8
  48. package/dist/api/design/windows/index.d.ts.map +1 -1
  49. package/dist/api/entity/buildableEnvelope.d.ts +84 -2
  50. package/dist/api/entity/buildableEnvelope.d.ts.map +1 -1
  51. package/dist/api/presentation/aiInspiration.d.ts +10 -10
  52. package/dist/api/presentation/annotate.d.ts +38 -22
  53. package/dist/api/presentation/annotate.d.ts.map +1 -1
  54. package/dist/api/presentation/drawingContract.d.ts +32 -0
  55. package/dist/api/presentation/drawingContract.d.ts.map +1 -0
  56. package/dist/api/presentation/drawings.d.ts +3523 -0
  57. package/dist/api/presentation/drawings.d.ts.map +1 -0
  58. package/dist/api/presentation/export.d.ts +23 -5
  59. package/dist/api/presentation/export.d.ts.map +1 -1
  60. package/dist/api/presentation/index.d.ts +41 -12
  61. package/dist/api/presentation/index.d.ts.map +1 -1
  62. package/dist/api/presentation/placedViews.d.ts +106 -6
  63. package/dist/api/presentation/placedViews.d.ts.map +1 -1
  64. package/dist/api/presentation/sections.d.ts +461 -0
  65. package/dist/api/presentation/sections.d.ts.map +1 -0
  66. package/dist/api/presentation/shapes.d.ts +2 -2
  67. package/dist/api/presentation/sheets.d.ts +175 -19
  68. package/dist/api/presentation/sheets.d.ts.map +1 -1
  69. package/dist/api/presentation/viewPresets.d.ts +222 -0
  70. package/dist/api/presentation/viewPresets.d.ts.map +1 -0
  71. package/dist/api/presentation/views.d.ts +141 -8
  72. package/dist/api/presentation/views.d.ts.map +1 -1
  73. package/dist/api/presentation/walkthroughs.d.ts +6 -6
  74. package/dist/errors/codes.d.ts +3 -1
  75. package/dist/errors/codes.d.ts.map +1 -1
  76. package/dist/index.cjs +3883 -2385
  77. package/dist/index.cjs.map +1 -1
  78. package/dist/index.js +3744 -2385
  79. package/dist/index.js.map +1 -1
  80. package/package.json +1 -1
  81. package/scripts/check-dist-fresh.mjs +22 -22
  82. package/scripts/generate-manifest.mjs +243 -238
  83. package/scripts/generate-manifest.test.mjs +303 -303
  84. package/src/api/analysis/daylight.ts +470 -470
  85. package/src/api/analysis/heatmaps.ts +683 -683
  86. package/src/api/analysis/illuminance.ts +155 -155
  87. package/src/api/analysis/index.ts +61 -61
  88. package/src/api/analysis/shadows.ts +183 -183
  89. package/src/api/analysis/solar.ts +237 -237
  90. package/src/api/analysis/sunlightHours.ts +211 -211
  91. package/src/api/analysis/sunpath.ts +83 -83
  92. package/src/api/analysis/weather.ts +179 -179
  93. package/src/api/core/buildings.ts +485 -485
  94. package/src/api/core/camera/index.ts +696 -667
  95. package/src/api/core/comment/index.ts +376 -376
  96. package/src/api/core/geom/create/index.ts +2139 -2133
  97. package/src/api/core/geom/delete/index.ts +84 -84
  98. package/src/api/core/geom/index.ts +35 -35
  99. package/src/api/core/geom/query/arc.ts +169 -169
  100. package/src/api/core/geom/query/brep.ts +621 -621
  101. package/src/api/core/geom/query/circle.ts +404 -404
  102. package/src/api/core/geom/query/contour.ts +540 -540
  103. package/src/api/core/geom/query/curve.ts +1102 -1102
  104. package/src/api/core/geom/query/edge.ts +130 -130
  105. package/src/api/core/geom/query/face.ts +508 -508
  106. package/src/api/core/geom/query/halfedge.ts +210 -210
  107. package/src/api/core/geom/query/index.ts +63 -63
  108. package/src/api/core/geom/query/profile.ts +473 -473
  109. package/src/api/core/geom/query/vertex.ts +205 -205
  110. package/src/api/core/geom/update/contour.ts +323 -317
  111. package/src/api/core/geom/update/curve.ts +209 -209
  112. package/src/api/core/geom/update/index.ts +29 -29
  113. package/src/api/core/geom/update/profile.ts +379 -379
  114. package/src/api/core/groups.ts +521 -521
  115. package/src/api/core/handles/index.ts +234 -234
  116. package/src/api/core/history/index.ts +84 -84
  117. package/src/api/core/index.ts +99 -99
  118. package/src/api/core/io/export/index.ts +126 -126
  119. package/src/api/core/io/import/index.ts +504 -504
  120. package/src/api/core/io/index.ts +42 -42
  121. package/src/api/core/io/job/index.ts +140 -140
  122. package/src/api/core/io/query/index.ts +71 -71
  123. package/src/api/core/io/terrain/index.ts +360 -360
  124. package/src/api/core/io/underlay/index.ts +705 -705
  125. package/src/api/core/layers.ts +540 -540
  126. package/src/api/core/math/index.ts +20 -20
  127. package/src/api/core/math/quat.ts +172 -172
  128. package/src/api/core/math/vec3.ts +179 -179
  129. package/src/api/core/mode/index.ts +108 -108
  130. package/src/api/core/project/index.ts +479 -479
  131. package/src/api/core/proposals/index.ts +570 -570
  132. package/src/api/core/storeys/index.ts +311 -308
  133. package/src/api/core/storeys/layers.ts +339 -339
  134. package/src/api/core/tags.ts +911 -911
  135. package/src/api/core/units/index.ts +164 -164
  136. package/src/api/core/user.ts +46 -46
  137. package/src/api/core/zoom/index.ts +64 -51
  138. package/src/api/design/bim.ts +210 -0
  139. package/src/api/design/boolean/index.ts +181 -179
  140. package/src/api/design/catalog.ts +203 -0
  141. package/src/api/design/create/bulk-items.ts +294 -254
  142. package/src/api/design/create/grids.ts +137 -137
  143. package/src/api/design/create/index.ts +2178 -1980
  144. package/src/api/design/create/opening-fields.ts +40 -37
  145. package/src/api/design/delete/index.ts +75 -74
  146. package/src/api/design/dimensions.ts +453 -453
  147. package/src/api/design/doors/index.ts +516 -500
  148. package/src/api/design/edit/index.ts +54 -54
  149. package/src/api/design/erase/index.ts +151 -151
  150. package/src/api/design/family.ts +1342 -704
  151. package/src/api/design/furniture/index.ts +319 -319
  152. package/src/api/design/grids.ts +237 -237
  153. package/src/api/design/index.ts +304 -274
  154. package/src/api/design/lock.ts +69 -69
  155. package/src/api/design/materials/index.ts +608 -608
  156. package/src/api/design/networks.ts +607 -0
  157. package/src/api/design/query/geometry/index.ts +319 -319
  158. package/src/api/design/query/grids.ts +197 -197
  159. package/src/api/design/query/index.ts +1236 -1226
  160. package/src/api/design/query/referenceLines.ts +52 -52
  161. package/src/api/design/query/spaces.ts +275 -275
  162. package/src/api/design/selection/index.ts +273 -273
  163. package/src/api/design/shared.ts +40 -40
  164. package/src/api/design/transform/index.ts +254 -254
  165. package/src/api/design/types/index.ts +163 -156
  166. package/src/api/design/update/index.ts +1096 -983
  167. package/src/api/design/visibility.ts +143 -143
  168. package/src/api/design/windows/index.ts +351 -333
  169. package/src/api/entity/buildableEnvelope.ts +397 -322
  170. package/src/api/entity/index.ts +30 -30
  171. package/src/api/entity/referenceLine.ts +235 -235
  172. package/src/api/entity/space.ts +612 -612
  173. package/src/api/entity/story.ts +517 -517
  174. package/src/api/index.ts +47 -47
  175. package/src/api/presentation/aiInspiration.ts +1116 -1116
  176. package/src/api/presentation/annotate.ts +417 -385
  177. package/src/api/presentation/camera.ts +289 -289
  178. package/src/api/presentation/diagrams.ts +194 -194
  179. package/src/api/presentation/drawingContract.ts +70 -0
  180. package/src/api/presentation/drawings.ts +1179 -0
  181. package/src/api/presentation/export.ts +134 -108
  182. package/src/api/presentation/import.ts +159 -159
  183. package/src/api/presentation/index.ts +160 -126
  184. package/src/api/presentation/placedViews.ts +1211 -1120
  185. package/src/api/presentation/sections.ts +420 -0
  186. package/src/api/presentation/shapes.ts +274 -274
  187. package/src/api/presentation/sheets.ts +746 -585
  188. package/src/api/presentation/slideshow.ts +134 -134
  189. package/src/api/presentation/tables.ts +84 -84
  190. package/src/api/presentation/viewPresets.ts +241 -0
  191. package/src/api/presentation/views.ts +742 -673
  192. package/src/api/presentation/walkthroughs.ts +1201 -1201
  193. package/src/api/program/adjacency.ts +164 -164
  194. package/src/api/program/areas.ts +408 -408
  195. package/src/api/program/classification.ts +138 -138
  196. package/src/api/program/cores.ts +83 -83
  197. package/src/api/program/departments.ts +517 -517
  198. package/src/api/program/index.ts +73 -73
  199. package/src/api/program/labels.ts +332 -332
  200. package/src/api/program/layout.ts +422 -422
  201. package/src/api/program/metadata.ts +364 -364
  202. package/src/api/program/metrics.ts +120 -120
  203. package/src/api/program/site.ts +748 -748
  204. package/src/api/program/spreadsheet.ts +2698 -2698
  205. package/src/api/workspace/index.ts +612 -612
  206. package/src/errors/codes.ts +143 -136
  207. package/src/errors/envelope.ts +75 -75
  208. package/src/errors/index.ts +21 -21
  209. package/src/errors/plugin-error.ts +134 -134
  210. package/src/handles.ts +297 -297
  211. package/src/host-utils.ts +67 -67
  212. package/src/index.ts +7 -7
  213. package/src/massParameters.ops.ts +246 -246
  214. package/src/massParameters.ts +427 -427
  215. package/src/types.ts +16 -16
  216. package/test/drawingContract.test.mjs +288 -0
  217. package/test/errors.test.mjs +185 -184
  218. package/test/massParameters.test.mjs +952 -952
  219. package/test/presentationViewSettings.test.mjs +85 -0
  220. package/tsconfig.json +22 -22
  221. package/tsup.config.ts +12 -12
@@ -1,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
+ }