@snaptrude/plugin-core 0.7.0 → 0.8.0

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 (133) hide show
  1. package/CHANGELOG.md +22 -0
  2. package/api-manifest.full.json +360 -19
  3. package/api-manifest.json +915 -37
  4. package/dist/api/core/camera/index.d.ts +208 -0
  5. package/dist/api/core/camera/index.d.ts.map +1 -0
  6. package/dist/api/core/comment/index.d.ts +105 -2
  7. package/dist/api/core/comment/index.d.ts.map +1 -1
  8. package/dist/api/core/geom/create/index.d.ts +13 -13
  9. package/dist/api/core/geom/delete/index.d.ts +8 -2
  10. package/dist/api/core/geom/delete/index.d.ts.map +1 -1
  11. package/dist/api/core/geom/query/arc.d.ts +5 -5
  12. package/dist/api/core/geom/query/brep.d.ts +18 -18
  13. package/dist/api/core/geom/query/circle.d.ts +18 -18
  14. package/dist/api/core/geom/query/contour.d.ts +20 -20
  15. package/dist/api/core/geom/query/curve.d.ts +49 -49
  16. package/dist/api/core/geom/query/edge.d.ts +5 -5
  17. package/dist/api/core/geom/query/face.d.ts +16 -16
  18. package/dist/api/core/geom/query/halfedge.d.ts +8 -8
  19. package/dist/api/core/geom/query/profile.d.ts +19 -19
  20. package/dist/api/core/geom/query/vertex.d.ts +8 -8
  21. package/dist/api/core/geom/update/contour.d.ts +14 -14
  22. package/dist/api/core/geom/update/curve.d.ts +7 -7
  23. package/dist/api/core/geom/update/profile.d.ts +16 -16
  24. package/dist/api/core/handles/index.d.ts +210 -0
  25. package/dist/api/core/handles/index.d.ts.map +1 -0
  26. package/dist/api/core/index.d.ts +15 -0
  27. package/dist/api/core/index.d.ts.map +1 -1
  28. package/dist/api/core/io/export/index.d.ts +132 -0
  29. package/dist/api/core/io/export/index.d.ts.map +1 -0
  30. package/dist/api/core/io/import/index.d.ts +1 -1
  31. package/dist/api/core/io/index.d.ts +5 -0
  32. package/dist/api/core/io/index.d.ts.map +1 -1
  33. package/dist/api/core/layers.d.ts +7 -7
  34. package/dist/api/core/proposals/index.d.ts +65 -9
  35. package/dist/api/core/proposals/index.d.ts.map +1 -1
  36. package/dist/api/core/user.d.ts +44 -0
  37. package/dist/api/core/user.d.ts.map +1 -0
  38. package/dist/api/design/boolean/index.d.ts +4 -4
  39. package/dist/api/design/create/index.d.ts +139 -44
  40. package/dist/api/design/create/index.d.ts.map +1 -1
  41. package/dist/api/design/doors/index.d.ts +36 -0
  42. package/dist/api/design/doors/index.d.ts.map +1 -1
  43. package/dist/api/design/edit/index.d.ts +1 -1
  44. package/dist/api/design/erase/index.d.ts +2 -2
  45. package/dist/api/design/furniture/index.d.ts +114 -3
  46. package/dist/api/design/furniture/index.d.ts.map +1 -1
  47. package/dist/api/design/index.d.ts +10 -0
  48. package/dist/api/design/index.d.ts.map +1 -1
  49. package/dist/api/design/materials/index.d.ts +111 -14
  50. package/dist/api/design/materials/index.d.ts.map +1 -1
  51. package/dist/api/design/query/index.d.ts +31 -1
  52. package/dist/api/design/query/index.d.ts.map +1 -1
  53. package/dist/api/design/query/spaces.d.ts +5 -5
  54. package/dist/api/design/transform/index.d.ts +83 -14
  55. package/dist/api/design/transform/index.d.ts.map +1 -1
  56. package/dist/api/design/types/index.d.ts +181 -0
  57. package/dist/api/design/types/index.d.ts.map +1 -0
  58. package/dist/api/design/update/index.d.ts +335 -2
  59. package/dist/api/design/update/index.d.ts.map +1 -1
  60. package/dist/api/design/visibility.d.ts +98 -0
  61. package/dist/api/design/visibility.d.ts.map +1 -0
  62. package/dist/api/entity/referenceLine.d.ts +2 -2
  63. package/dist/api/entity/space.d.ts +19 -19
  64. package/dist/api/entity/story.d.ts +128 -15
  65. package/dist/api/entity/story.d.ts.map +1 -1
  66. package/dist/api/presentation/aiInspiration.d.ts +1967 -7
  67. package/dist/api/presentation/aiInspiration.d.ts.map +1 -1
  68. package/dist/api/presentation/annotate.d.ts +448 -0
  69. package/dist/api/presentation/annotate.d.ts.map +1 -0
  70. package/dist/api/presentation/diagrams.d.ts +49 -8
  71. package/dist/api/presentation/diagrams.d.ts.map +1 -1
  72. package/dist/api/presentation/export.d.ts +104 -0
  73. package/dist/api/presentation/export.d.ts.map +1 -0
  74. package/dist/api/presentation/index.d.ts +40 -3
  75. package/dist/api/presentation/index.d.ts.map +1 -1
  76. package/dist/api/presentation/sheets.d.ts +410 -13
  77. package/dist/api/presentation/sheets.d.ts.map +1 -1
  78. package/dist/api/presentation/views.d.ts +165 -10
  79. package/dist/api/presentation/views.d.ts.map +1 -1
  80. package/dist/api/program/areas.d.ts +63 -3
  81. package/dist/api/program/areas.d.ts.map +1 -1
  82. package/dist/api/program/cores.d.ts +3 -99
  83. package/dist/api/program/cores.d.ts.map +1 -1
  84. package/dist/api/program/index.d.ts +2 -2
  85. package/dist/api/program/index.d.ts.map +1 -1
  86. package/dist/api/program/layout.d.ts +172 -12
  87. package/dist/api/program/layout.d.ts.map +1 -1
  88. package/dist/api/program/site.d.ts +11 -8
  89. package/dist/api/program/site.d.ts.map +1 -1
  90. package/dist/api/program/spreadsheet.d.ts +105 -13
  91. package/dist/api/program/spreadsheet.d.ts.map +1 -1
  92. package/dist/handles.d.ts +64 -25
  93. package/dist/handles.d.ts.map +1 -1
  94. package/dist/index.cjs +2502 -1466
  95. package/dist/index.cjs.map +1 -1
  96. package/dist/index.js +2369 -1461
  97. package/dist/index.js.map +1 -1
  98. package/package.json +1 -1
  99. package/src/api/core/camera/index.ts +212 -0
  100. package/src/api/core/comment/index.ts +120 -2
  101. package/src/api/core/geom/delete/index.ts +6 -0
  102. package/src/api/core/handles/index.ts +233 -0
  103. package/src/api/core/index.ts +15 -0
  104. package/src/api/core/io/export/index.ts +124 -0
  105. package/src/api/core/io/index.ts +5 -0
  106. package/src/api/core/proposals/index.ts +71 -11
  107. package/src/api/core/user.ts +46 -0
  108. package/src/api/design/create/index.ts +166 -36
  109. package/src/api/design/doors/index.ts +40 -0
  110. package/src/api/design/furniture/index.ts +127 -3
  111. package/src/api/design/index.ts +10 -0
  112. package/src/api/design/materials/index.ts +157 -30
  113. package/src/api/design/query/index.ts +33 -7
  114. package/src/api/design/transform/index.ts +89 -12
  115. package/src/api/design/types/index.ts +156 -0
  116. package/src/api/design/update/index.ts +402 -6
  117. package/src/api/design/visibility.ts +109 -0
  118. package/src/api/entity/story.ts +141 -15
  119. package/src/api/presentation/aiInspiration.ts +761 -7
  120. package/src/api/presentation/annotate.ts +360 -0
  121. package/src/api/presentation/diagrams.ts +53 -8
  122. package/src/api/presentation/export.ts +104 -0
  123. package/src/api/presentation/index.ts +48 -3
  124. package/src/api/presentation/sheets.ts +346 -13
  125. package/src/api/presentation/views.ts +164 -12
  126. package/src/api/program/areas.ts +57 -6
  127. package/src/api/program/cores.ts +3 -91
  128. package/src/api/program/index.ts +2 -2
  129. package/src/api/program/layout.ts +182 -12
  130. package/src/api/program/site.ts +11 -8
  131. package/src/api/program/spreadsheet.ts +125 -29
  132. package/src/handles.ts +77 -13
  133. package/tsconfig.json +7 -2
@@ -6,12 +6,14 @@ import { PluginApiReturn } from "../../types"
6
6
  *
7
7
  * A **view** is a saved camera/plan: a sheet-ready 2D plan or a saved 3D view.
8
8
  * A plugin can list and read views, capture them to images, activate one (move
9
- * the camera to it), save the current camera as a new view, and read/update a
10
- * view's display settings (background, color mode, axis, edges, labels).
9
+ * the camera to it), save the current camera as a new view, rename or delete a
10
+ * saved view, and read/update a view's display settings (background, color
11
+ * mode, view mode, axis, edges, labels). Each view carries the `storey` it was
12
+ * saved on.
11
13
  *
12
14
  * `list`/`get`/`getActive`/`capture`/`getSettings` are reads;
13
- * `setActive`/`create`/`updateSettings` are writes (a view is a camera bookmark
14
- * — not geometry).
15
+ * `setActive`/`create`/`rename`/`delete`/`updateSettings` are writes (a view is
16
+ * a camera bookmark — not geometry).
15
17
  *
16
18
  * Accessed via `snaptrude.presentation.views`.
17
19
  */
@@ -135,28 +137,35 @@ export abstract class PluginPresentationViewsApi {
135
137
  * Creates a camera bookmark (not geometry) from where the camera is now.
136
138
  *
137
139
  * @param name - Name for the new view (a default is used when omitted).
138
- * @param options - Optional `kind`: what kind of view to save (default `"view"`).
140
+ * @param options - Optional `kind` (what kind of view to save, default
141
+ * `"view"`) and `storey` (save the view on a specific storey — the storey is
142
+ * activated first, matching the storey the view is captured on; when omitted
143
+ * the current active storey is used).
139
144
  * @returns The newly created {@linkcode PluginPresentationView}.
140
- * @throws If the view could not be saved.
145
+ * @throws If `storey` is given but no such storey exists, or the view could
146
+ * not be saved.
141
147
  *
142
148
  * @examplePrompt Save the current view as Lobby Perspective
143
149
  * @examplePrompt Create a new saved view from where I'm looking
144
150
  * @examplePrompt Bookmark this camera angle
145
151
  * @examplePrompt Save the current 2D plan as a view
152
+ * @examplePrompt Save a view on the second storey
146
153
  *
147
154
  * # Example
148
155
  * ```ts
149
156
  * const view = await snaptrude.presentation.views.create("Lobby")
157
+ * // …or capture the view on a specific storey
158
+ * const level2 = await snaptrude.presentation.views.create("Level 2", { storey: 2 })
150
159
  * ```
151
160
  */
152
161
  public abstract create(
153
162
  name?: string,
154
- options?: { kind?: "view" | "sitePlan" },
163
+ options?: { kind?: "view" | "sitePlan"; storey?: number },
155
164
  ): PluginApiReturn<PluginPresentationViewsCreateResult>
156
165
 
157
166
  /**
158
- * Read a saved view's display settings (background, color mode, axis, edges,
159
- * labels).
167
+ * Read a saved view's display settings (background, color mode, view mode,
168
+ * axis, edges, labels).
160
169
  *
161
170
  * @param viewId - The id of the view to read settings for.
162
171
  * @returns The view's {@linkcode PluginPresentationViewSettings}, or `null` if
@@ -206,19 +215,30 @@ export abstract class PluginPresentationViewsApi {
206
215
  * {@linkcode PluginPresentationViewsApi.getSettings}, so read-then-write
207
216
  * round-trips a tag-based color scheme unchanged.
208
217
  *
218
+ * `viewMode` (`"perspective"` | `"isometric"`) applies to **3D views only** —
219
+ * a 2D plan is always orthographic, so a `viewMode: "perspective"` patch on a
220
+ * 2D view is rejected. `"isometric"` on a 2D plan is accepted as a no-op (the
221
+ * plan is already orthographic), so writing back exactly what
222
+ * {@linkcode PluginPresentationViewsApi.getSettings} returned is always a
223
+ * no-op. On the active view the camera switches projection live (the same
224
+ * toggle the view-settings modal runs); on other views the mode is applied
225
+ * the next time the view is activated.
226
+ *
209
227
  * @param viewId - The id of the view to update.
210
228
  * @param settings - A partial {@linkcode PluginPresentationViewSettings}; any
211
229
  * omitted field is left unchanged.
212
230
  * @returns The updated view's `id`.
213
- * @throws If writes are disabled, no view has the given id, or the patch is
231
+ * @throws If writes are disabled, no view has the given id, the patch is
214
232
  * contradictory (`showLabels: false` with a non-empty `labels`, or
215
- * `showLabels: true` with an explicitly empty `labels` list).
233
+ * `showLabels: true` with an explicitly empty `labels` list), or
234
+ * `viewMode: "perspective"` is patched on a 2D plan view.
216
235
  *
217
236
  * @examplePrompt Switch this view to monochrome color mode
218
237
  * @examplePrompt Turn off the axis in the Ground Floor view
219
238
  * @examplePrompt Set the background of the active view to white
220
239
  * @examplePrompt Show area labels on this view
221
240
  * @examplePrompt Enable hidden-line mode for the section view
241
+ * @examplePrompt Make the 3D view orthographic instead of perspective
222
242
  *
223
243
  * # Example
224
244
  * ```ts
@@ -226,12 +246,70 @@ export abstract class PluginPresentationViewsApi {
226
246
  * colorMode: "monochrome",
227
247
  * showAxis: false,
228
248
  * })
249
+ * // switch a 3D view to an isometric (orthographic) projection
250
+ * await snaptrude.presentation.views.updateSettings("view_123", {
251
+ * viewMode: "isometric",
252
+ * })
229
253
  * ```
230
254
  */
231
255
  public abstract updateSettings(
232
256
  viewId: string,
233
257
  settings: Partial<PluginPresentationViewSettings>,
234
258
  ): PluginApiReturn<PluginPresentationViewsUpdateSettingsResult>
259
+
260
+ /**
261
+ * Rename a saved view.
262
+ *
263
+ * Sets the view's display name — the same label the views panel shows and
264
+ * that `list`/`get` read back. Names must be unique within the proposal and
265
+ * cannot contain the characters `\ : { } [ ] | ; < > ? ~`.
266
+ *
267
+ * @param viewId - The id of the view to rename.
268
+ * @param name - The new display name (non-empty after trimming).
269
+ * @returns The updated {@linkcode PluginPresentationView}.
270
+ * @throws If writes are disabled, no view has the given id, the name is
271
+ * empty/invalid, or another view in the proposal already has that name.
272
+ *
273
+ * @examplePrompt Rename the view Lobby to Entrance Lobby
274
+ * @examplePrompt Call this view Ground Floor Plan
275
+ * @examplePrompt Change the active view's name to Final
276
+ *
277
+ * # Example
278
+ * ```ts
279
+ * const view = await snaptrude.presentation.views.rename("view_123", "Entrance")
280
+ * ```
281
+ */
282
+ public abstract rename(
283
+ viewId: string,
284
+ name: string,
285
+ ): PluginApiReturn<PluginPresentationViewsRenameResult>
286
+
287
+ /**
288
+ * Delete a saved view.
289
+ *
290
+ * Removes the view from the project and the views panel (the panel's own
291
+ * delete action). If the deleted view was active, the product falls back to
292
+ * the default plan/3D view. Default views (the built-in plan/3D/site-plan
293
+ * entries) cannot be deleted.
294
+ *
295
+ * @param viewId - The id of the view to delete.
296
+ * @returns The id of the deleted view
297
+ * (a {@linkcode PluginPresentationViewsDeleteResult}).
298
+ * @throws If writes are disabled, no view has the given id, or the view is a
299
+ * default view.
300
+ *
301
+ * @examplePrompt Delete the view named Old Draft
302
+ * @examplePrompt Remove this saved view
303
+ * @examplePrompt Get rid of the Lobby camera bookmark
304
+ *
305
+ * # Example
306
+ * ```ts
307
+ * const { id } = await snaptrude.presentation.views.delete("view_123")
308
+ * ```
309
+ */
310
+ public abstract delete(
311
+ viewId: string,
312
+ ): PluginApiReturn<PluginPresentationViewsDeleteResult>
235
313
  }
236
314
 
237
315
  /**
@@ -251,12 +329,14 @@ export type PluginPresentationViewType = z.infer<
251
329
  * | `name` | `string` | Display name |
252
330
  * | `type` | `"2d" \| "3d"` | Whether this is a 2D plan view or a 3D view |
253
331
  * | `isActive` | `boolean` | Whether this view is the currently active view |
332
+ * | `storey` | `number \| null` | The storey this view was saved on (`null` on older views saved without one) |
254
333
  */
255
334
  export const PluginPresentationView = z.object({
256
335
  id: z.string(),
257
336
  name: z.string(),
258
337
  type: PluginPresentationViewType,
259
338
  isActive: z.boolean(),
339
+ storey: z.number().nullable(),
260
340
  })
261
341
  export type PluginPresentationView = z.infer<typeof PluginPresentationView>
262
342
 
@@ -366,10 +446,12 @@ export type PluginPresentationViewsSetActiveResult = z.infer<
366
446
  * |---|---|---|
367
447
  * | `name` | `string \| undefined` | Name for the new view (a default is used when omitted) |
368
448
  * | `kind` | `"view" \| "sitePlan" \| undefined` | What kind of view to save (default `"view"`). `"plan"` is not offered — the host cannot create a plan view without a `planId` this API does not carry. |
449
+ * | `storey` | `number \| undefined` | Save the view on this storey (activated before capture); defaults to the current active storey |
369
450
  */
370
451
  export const PluginPresentationViewsCreateArgs = z.object({
371
452
  name: z.string().optional(),
372
453
  kind: z.enum(["view", "sitePlan"]).optional(),
454
+ storey: z.number().optional(),
373
455
  })
374
456
  export type PluginPresentationViewsCreateArgs = z.infer<
375
457
  typeof PluginPresentationViewsCreateArgs
@@ -421,6 +503,22 @@ export type PluginPresentationViewLabel = z.infer<
421
503
  typeof PluginPresentationViewLabel
422
504
  >
423
505
 
506
+ /**
507
+ * A view's camera projection: perspective, or isometric (orthographic).
508
+ *
509
+ * | Value | Meaning |
510
+ * |---|---|
511
+ * | `perspective` | Perspective projection (vanishing points) |
512
+ * | `isometric` | Orthographic projection (no perspective distortion) |
513
+ *
514
+ * Applies to 3D views; a 2D plan view is always orthographic and reads
515
+ * `"isometric"`.
516
+ */
517
+ export const PluginPresentationViewMode = z.enum(["perspective", "isometric"])
518
+ export type PluginPresentationViewMode = z.infer<
519
+ typeof PluginPresentationViewMode
520
+ >
521
+
424
522
  /**
425
523
  * A view's display settings.
426
524
  *
@@ -428,6 +526,7 @@ export type PluginPresentationViewLabel = z.infer<
428
526
  * |---|---|---|
429
527
  * | `backgroundColor` | `string` | Canvas background as a hex color (e.g. `#ffffff`) |
430
528
  * | `colorMode` | {@linkcode PluginPresentationViewColorMode} | How the scene is colored (including `tag:<categoryId>` schemes) |
529
+ * | `viewMode` | {@linkcode PluginPresentationViewMode} | Camera projection — `"perspective"` or `"isometric"` (orthographic). Writable on 3D views only; a 2D plan always reads `"isometric"` and accepts only `"isometric"` (a no-op) |
431
530
  * | `showAxis` | `boolean` | Whether the X/Y/Z axes are shown |
432
531
  * | `showEdges` | `boolean` | Whether edges are shown; `false` = hidden-line rendering |
433
532
  * | `showLabels` | `boolean` | Master label switch — whether on-canvas labels are shown at all. `true` always pairs with a non-empty `labels` selection (labels render only while the selection is non-empty; there is no labels-on-with-empty-selection state) |
@@ -436,6 +535,7 @@ export type PluginPresentationViewLabel = z.infer<
436
535
  export const PluginPresentationViewSettings = z.object({
437
536
  backgroundColor: z.string(),
438
537
  colorMode: PluginPresentationViewColorMode,
538
+ viewMode: PluginPresentationViewMode,
439
539
  showAxis: z.boolean(),
440
540
  showEdges: z.boolean(),
441
541
  showLabels: z.boolean(),
@@ -488,7 +588,9 @@ export const PluginPresentationViewsUpdateSettingsArgs = z
488
588
  })
489
589
  .refine(
490
590
  (v) =>
491
- !(v.settings.showLabels === false && (v.settings.labels?.length ?? 0) > 0),
591
+ !(
592
+ v.settings.showLabels === false && (v.settings.labels?.length ?? 0) > 0
593
+ ),
492
594
  {
493
595
  message:
494
596
  "Contradictory patch: labels cannot be set while showLabels is false",
@@ -517,3 +619,53 @@ export const PluginPresentationViewsUpdateSettingsResult = z.object({
517
619
  export type PluginPresentationViewsUpdateSettingsResult = z.infer<
518
620
  typeof PluginPresentationViewsUpdateSettingsResult
519
621
  >
622
+
623
+ /**
624
+ * Arguments for {@linkcode PluginPresentationViewsApi.rename}.
625
+ *
626
+ * | Property | Type | Description |
627
+ * |---|---|---|
628
+ * | `id` | `string` | The id of the view to rename |
629
+ * | `name` | `string` | New display name (non-empty after trimming) |
630
+ */
631
+ export const PluginPresentationViewsRenameArgs = z.object({
632
+ id: z.string(),
633
+ name: z.string().trim().min(1),
634
+ })
635
+ export type PluginPresentationViewsRenameArgs = z.infer<
636
+ typeof PluginPresentationViewsRenameArgs
637
+ >
638
+
639
+ /** Result of {@linkcode PluginPresentationViewsApi.rename} — the renamed view. */
640
+ export const PluginPresentationViewsRenameResult = PluginPresentationView
641
+ export type PluginPresentationViewsRenameResult = z.infer<
642
+ typeof PluginPresentationViewsRenameResult
643
+ >
644
+
645
+ /**
646
+ * Arguments for {@linkcode PluginPresentationViewsApi.delete}.
647
+ *
648
+ * | Property | Type | Description |
649
+ * |---|---|---|
650
+ * | `id` | `string` | The id of the view to delete |
651
+ */
652
+ export const PluginPresentationViewsDeleteArgs = z.object({
653
+ id: z.string(),
654
+ })
655
+ export type PluginPresentationViewsDeleteArgs = z.infer<
656
+ typeof PluginPresentationViewsDeleteArgs
657
+ >
658
+
659
+ /**
660
+ * Result of {@linkcode PluginPresentationViewsApi.delete}.
661
+ *
662
+ * | Property | Type | Description |
663
+ * |---|---|---|
664
+ * | `id` | `string` | Id of the deleted view |
665
+ */
666
+ export const PluginPresentationViewsDeleteResult = z.object({
667
+ id: z.string(),
668
+ })
669
+ export type PluginPresentationViewsDeleteResult = z.infer<
670
+ typeof PluginPresentationViewsDeleteResult
671
+ >
@@ -29,9 +29,14 @@ import { ComponentHandle } from "../../handles"
29
29
  * PluginProgramAreasApi.update}); the two are the same ratio, one measured and
30
30
  * one intended. The surface speaks **FAR only** — there is no FSI alias.
31
31
  *
32
- * Reads return plain records and never throw. The only write —
33
- * {@linkcode PluginProgramAreasApi.update} is a non-undoable settings write
34
- * for the FAR inputs.
32
+ * Reads return plain records and never throw. Because the engine only recomputes
33
+ * the breakdown live while the Area sidebar is open, a headless plugin should call
34
+ * {@linkcode PluginProgramAreasApi.refresh} first to guarantee the reads are fresh.
35
+ * The only write — {@linkcode PluginProgramAreasApi.update} — is a non-undoable
36
+ * settings write for the FAR inputs. With an active design option (proposal),
37
+ * those inputs are per-option: `update` writes and the reads report the active
38
+ * option's own target FAR / site area / deviation, matching the product's Area
39
+ * settings dialog.
35
40
  *
36
41
  * Accessed via `snaptrude.program.areas`.
37
42
  */
@@ -129,6 +134,13 @@ export abstract class PluginProgramAreasApi {
129
134
  * area, and the allowed deviation. This is a **non-undoable settings write**
130
135
  * (persisted with the project). `achievedFar` recomputes from these.
131
136
  *
137
+ * **Design options:** when a design option (proposal) is active, the FAR
138
+ * inputs are **scoped to that design option** — exactly like the product's
139
+ * Area settings dialog. `update` writes the active option's settings (each
140
+ * option keeps its own target FAR / site area / deviation) and the reads
141
+ * ({@linkcode PluginProgramAreasApi.get} etc.) report that same scope.
142
+ * Without design options there is a single project-wide set of FAR inputs.
143
+ *
132
144
  * @param options - Any of `targetFar`, `siteArea`, `deviation`; omitted fields
133
145
  * are left unchanged.
134
146
  * @returns The recomputed {@linkcode PluginProgramAreaSummary}.
@@ -144,9 +156,39 @@ export abstract class PluginProgramAreasApi {
144
156
  * console.log(s.achievedFar, s.targetFar)
145
157
  * ```
146
158
  */
147
- public abstract update(
148
- options?: { targetFar?: number; siteArea?: number; deviation?: number },
149
- ): PluginApiReturn<PluginProgramAreasUpdateResult>
159
+ public abstract update(options?: {
160
+ targetFar?: number
161
+ siteArea?: number
162
+ deviation?: number
163
+ }): PluginApiReturn<PluginProgramAreasUpdateResult>
164
+
165
+ /**
166
+ * Force the area breakdown to recompute, then return the fresh summary.
167
+ *
168
+ * The engine recomputes the carpet / built-up / FAR totals live **only while the
169
+ * Area sidebar is open**. A plugin running with the sidebar closed can therefore
170
+ * read a stale — or never-computed — snapshot from {@linkcode
171
+ * PluginProgramAreasApi.get} / {@linkcode PluginProgramAreasApi.list}. Call
172
+ * `refresh` first to guarantee those reads reflect the current model. It is a
173
+ * read (no write gate) — it recomputes derived totals, it does not change the model.
174
+ *
175
+ * **Cost:** a full pass over every space, floor and mass in the active structure.
176
+ * Not free on large models — call it once before a batch of reads, not per read.
177
+ *
178
+ * @returns The freshly-recomputed {@linkcode PluginProgramAreaSummary}.
179
+ *
180
+ * @examplePrompt Recompute the area totals before I read them
181
+ * @examplePrompt Refresh the FAR numbers
182
+ * @examplePrompt Make sure the area breakdown is up to date
183
+ *
184
+ * # Example
185
+ * ```ts
186
+ * const s = await snaptrude.program.areas.refresh()
187
+ * const { groups } = await snaptrude.program.areas.list("storeys") // now fresh
188
+ * console.log(s.builtUp, groups.length)
189
+ * ```
190
+ */
191
+ public abstract refresh(): PluginApiReturn<PluginProgramAreasRefreshResult>
150
192
  }
151
193
 
152
194
  /**
@@ -355,3 +397,12 @@ export const PluginProgramAreasUpdateResult = PluginProgramAreaSummary
355
397
  export type PluginProgramAreasUpdateResult = z.infer<
356
398
  typeof PluginProgramAreasUpdateResult
357
399
  >
400
+
401
+ /**
402
+ * Result of {@linkcode PluginProgramAreasApi.refresh} — the freshly-recomputed
403
+ * program area summary.
404
+ */
405
+ export const PluginProgramAreasRefreshResult = PluginProgramAreaSummary
406
+ export type PluginProgramAreasRefreshResult = z.infer<
407
+ typeof PluginProgramAreasRefreshResult
408
+ >
@@ -5,13 +5,9 @@ import { PluginApiReturn } from "../../types"
5
5
  * Program cores — the building's vertical-circulation cores (lift / stair / shaft
6
6
  * shells).
7
7
  *
8
- * Read the cores in the scene, test whether a space is a core, and trigger core
9
- * generation from a layout. `create` is a **thin trigger**: the program hands a
10
- * core layout to the core-generation engine, which authors the geometry — the
11
- * core geometry itself is owned by the geometry layer, not here (the exact
12
- * layout ↔ engine payload is coordinated with the geometry owner).
13
- *
14
- * `list`/`isCore` are reads; `create` triggers generation.
8
+ * Read the cores in the scene and test whether a space is a core. Both are reads;
9
+ * there is no core-generation trigger on this surface (core geometry is owned by
10
+ * the geometry layer, not here).
15
11
  *
16
12
  * Accessed via `snaptrude.program.cores`.
17
13
  */
@@ -52,37 +48,6 @@ export abstract class PluginProgramCoresApi {
52
48
  * ```
53
49
  */
54
50
  public abstract isCore(id: string): PluginApiReturn<boolean>
55
-
56
- /**
57
- * Generate core geometry from a layout (thin trigger).
58
- *
59
- * Hands the core layout to the core-generation engine and returns how many core
60
- * elements were created. The geometry is authored by the engine, not here.
61
- * _(Authored ahead — optional until the host's geometry adapter lands; the
62
- * reads {@linkcode PluginProgramCoresApi.list}/{@linkcode PluginProgramCoresApi.isCore}
63
- * are live.)_
64
- *
65
- * @param cores - The {@linkcode PluginProgramCoreSpec} layout of cores to
66
- * generate.
67
- * @param lengthUnit - Unit of the spec dimensions (default project unit).
68
- * @returns A {@linkcode PluginProgramCoresCreateResult} with the created count.
69
- * @throws If the layout could not be realized.
70
- *
71
- * @examplePrompt Generate the building cores from this layout
72
- * @examplePrompt Place the elevator and stair cores
73
- * @examplePrompt Create the service core shells
74
- *
75
- * # Example
76
- * ```ts
77
- * await snaptrude.program.cores.create([
78
- * { type: "lift", position: { x: 0, y: 0, z: 0 }, width: 3, depth: 4 },
79
- * ])
80
- * ```
81
- */
82
- public create?: (
83
- cores: PluginProgramCoreSpec[],
84
- lengthUnit?: "mm" | "m" | "ft",
85
- ) => PluginApiReturn<PluginProgramCoresCreateResult>
86
51
  }
87
52
 
88
53
  /**
@@ -116,56 +81,3 @@ export const PluginProgramCoresIsCoreArgs = z.object({
116
81
  export type PluginProgramCoresIsCoreArgs = z.infer<
117
82
  typeof PluginProgramCoresIsCoreArgs
118
83
  >
119
-
120
- /**
121
- * One core to generate. The geometry layer interprets this layout (the exact
122
- * fields are coordinated with the geometry owner).
123
- *
124
- * | Property | Type | Description |
125
- * |---|---|---|
126
- * | `type` | `string \| undefined` | Core kind (e.g. `"lift"`, `"stair"`, `"shaft"`) |
127
- * | `position` | `{ x; y; z }` | Base position of the core |
128
- * | `width` | `number` | Core width, in `lengthUnit` |
129
- * | `depth` | `number` | Core depth, in `lengthUnit` |
130
- * | `fromStorey` | `number \| undefined` | First storey the core spans |
131
- * | `toStorey` | `number \| undefined` | Last storey the core spans |
132
- */
133
- export const PluginProgramCoreSpec = z.object({
134
- type: z.string().optional(),
135
- position: z.object({ x: z.number(), y: z.number(), z: z.number() }),
136
- width: z.number(),
137
- depth: z.number(),
138
- fromStorey: z.number().optional(),
139
- toStorey: z.number().optional(),
140
- })
141
- export type PluginProgramCoreSpec = z.infer<typeof PluginProgramCoreSpec>
142
-
143
- /**
144
- * Arguments for {@linkcode PluginProgramCoresApi.create}.
145
- *
146
- * | Property | Type | Description |
147
- * |---|---|---|
148
- * | `cores` | {@linkcode PluginProgramCoreSpec}`[]` | The cores to generate |
149
- * | `lengthUnit` | `"mm" \| "m" \| "ft" \| undefined` | Unit of the spec dimensions (default project unit) |
150
- */
151
- export const PluginProgramCoresCreateArgs = z.object({
152
- cores: z.array(PluginProgramCoreSpec),
153
- lengthUnit: z.enum(["mm", "m", "ft"]).optional(),
154
- })
155
- export type PluginProgramCoresCreateArgs = z.infer<
156
- typeof PluginProgramCoresCreateArgs
157
- >
158
-
159
- /**
160
- * Result of {@linkcode PluginProgramCoresApi.create}.
161
- *
162
- * | Property | Type | Description |
163
- * |---|---|---|
164
- * | `createdCount` | `number` | Number of core elements created |
165
- */
166
- export const PluginProgramCoresCreateResult = z.object({
167
- createdCount: z.number(),
168
- })
169
- export type PluginProgramCoresCreateResult = z.infer<
170
- typeof PluginProgramCoresCreateResult
171
- >
@@ -24,7 +24,7 @@ import { PluginProgramAreasApi } from "./areas"
24
24
  * - {@linkcode PluginProgramApi.areas} — FAR / built-up-area rollup and groupings
25
25
  * - {@linkcode PluginProgramApi.spreadsheet} — Render program data to sheets and read it back
26
26
  * - {@linkcode PluginProgramApi.site} — Read the site/plot planning context
27
- * - {@linkcode PluginProgramApi.cores} — Read & trigger vertical-circulation cores
27
+ * - {@linkcode PluginProgramApi.cores} — Read & predicate vertical-circulation cores (reads only)
28
28
  * - {@linkcode PluginProgramApi.classification} — Classification catalog + display tags
29
29
  *
30
30
  * Accessed via `snaptrude.program`.
@@ -44,7 +44,7 @@ export abstract class PluginProgramApi {
44
44
  public abstract spreadsheet: PluginProgramSpreadsheetApi
45
45
  /** Site/plot planning context — total area, parcel footprints, geo rings. See {@linkcode PluginProgramSiteApi}. */
46
46
  public abstract site: PluginProgramSiteApi
47
- /** Vertical-circulation cores — read & predicate (live); generation trigger is optional. See {@linkcode PluginProgramCoresApi}. */
47
+ /** Vertical-circulation cores — read & predicate (reads only). See {@linkcode PluginProgramCoresApi}. */
48
48
  public abstract cores: PluginProgramCoresApi
49
49
  /** Classification catalog (space/area/mass types) + display tags. See {@linkcode PluginProgramClassificationApi}. */
50
50
  public abstract classification: PluginProgramClassificationApi