@snaptrude/plugin-core 0.7.1 → 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 (130) hide show
  1. package/CHANGELOG.md +14 -0
  2. package/api-manifest.full.json +6442 -0
  3. package/api-manifest.json +2029 -128
  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/annotate.d.ts +448 -0
  67. package/dist/api/presentation/annotate.d.ts.map +1 -0
  68. package/dist/api/presentation/diagrams.d.ts +49 -8
  69. package/dist/api/presentation/diagrams.d.ts.map +1 -1
  70. package/dist/api/presentation/export.d.ts +104 -0
  71. package/dist/api/presentation/export.d.ts.map +1 -0
  72. package/dist/api/presentation/index.d.ts +38 -0
  73. package/dist/api/presentation/index.d.ts.map +1 -1
  74. package/dist/api/presentation/sheets.d.ts +410 -13
  75. package/dist/api/presentation/sheets.d.ts.map +1 -1
  76. package/dist/api/presentation/views.d.ts +165 -10
  77. package/dist/api/presentation/views.d.ts.map +1 -1
  78. package/dist/api/program/areas.d.ts +63 -3
  79. package/dist/api/program/areas.d.ts.map +1 -1
  80. package/dist/api/program/cores.d.ts +3 -99
  81. package/dist/api/program/cores.d.ts.map +1 -1
  82. package/dist/api/program/index.d.ts +2 -2
  83. package/dist/api/program/index.d.ts.map +1 -1
  84. package/dist/api/program/layout.d.ts +172 -12
  85. package/dist/api/program/layout.d.ts.map +1 -1
  86. package/dist/api/program/site.d.ts +11 -8
  87. package/dist/api/program/site.d.ts.map +1 -1
  88. package/dist/api/program/spreadsheet.d.ts +105 -13
  89. package/dist/api/program/spreadsheet.d.ts.map +1 -1
  90. package/dist/handles.d.ts +64 -25
  91. package/dist/handles.d.ts.map +1 -1
  92. package/dist/index.cjs +2316 -1644
  93. package/dist/index.cjs.map +1 -1
  94. package/dist/index.js +2224 -1639
  95. package/dist/index.js.map +1 -1
  96. package/package.json +1 -1
  97. package/src/api/core/camera/index.ts +212 -0
  98. package/src/api/core/comment/index.ts +120 -2
  99. package/src/api/core/geom/delete/index.ts +6 -0
  100. package/src/api/core/handles/index.ts +233 -0
  101. package/src/api/core/index.ts +15 -0
  102. package/src/api/core/io/export/index.ts +124 -0
  103. package/src/api/core/io/index.ts +5 -0
  104. package/src/api/core/proposals/index.ts +71 -11
  105. package/src/api/core/user.ts +46 -0
  106. package/src/api/design/create/index.ts +166 -36
  107. package/src/api/design/doors/index.ts +40 -0
  108. package/src/api/design/furniture/index.ts +127 -3
  109. package/src/api/design/index.ts +10 -0
  110. package/src/api/design/materials/index.ts +157 -30
  111. package/src/api/design/query/index.ts +33 -7
  112. package/src/api/design/transform/index.ts +89 -12
  113. package/src/api/design/types/index.ts +156 -0
  114. package/src/api/design/update/index.ts +402 -6
  115. package/src/api/design/visibility.ts +109 -0
  116. package/src/api/entity/story.ts +141 -15
  117. package/src/api/presentation/annotate.ts +360 -0
  118. package/src/api/presentation/diagrams.ts +53 -8
  119. package/src/api/presentation/export.ts +104 -0
  120. package/src/api/presentation/index.ts +46 -0
  121. package/src/api/presentation/sheets.ts +346 -13
  122. package/src/api/presentation/views.ts +164 -12
  123. package/src/api/program/areas.ts +57 -6
  124. package/src/api/program/cores.ts +3 -91
  125. package/src/api/program/index.ts +2 -2
  126. package/src/api/program/layout.ts +182 -12
  127. package/src/api/program/site.ts +11 -8
  128. package/src/api/program/spreadsheet.ts +125 -29
  129. package/src/handles.ts +77 -13
  130. package/tsconfig.json +7 -2
package/api-manifest.json CHANGED
@@ -1,4 +1,244 @@
1
1
  [
2
+ {
3
+ "path": "analysis.heatmaps.isActive",
4
+ "namespace": "analysis.heatmaps",
5
+ "summary": "Is a plugin heatmap currently showing?",
6
+ "examplePrompts": [
7
+ "Is my heatmap still showing?",
8
+ "Check whether the custom heatmap is active",
9
+ "Do I need to re-render the wind overlay?\n\n# Example\n```ts\nif (!(await snaptrude.analysis.heatmaps.isActive())) {\nawait snaptrude.analysis.heatmaps.renderGrid(cells, 2)\n}\n```"
10
+ ],
11
+ "argsType": null,
12
+ "resultType": "boolean"
13
+ },
14
+ {
15
+ "path": "analysis.heatmaps.renderGrid",
16
+ "namespace": "analysis.heatmaps",
17
+ "summary": "Render a grid heatmap — a coloured mesh from point samples.",
18
+ "examplePrompts": [
19
+ "Overlay my CFD wind simulation results on the site",
20
+ "Render a noise-level grid around the building",
21
+ "Show these sampled microclimate values as a colored grid\n\n# Example\n```ts\n// World coordinates are y-up: a ground-level field varies in x/z at y = 0.\nawait snaptrude.analysis.heatmaps.renderGrid(\nsamples.map((s) => ({ position: { x: s.x, y: 0, z: s.z }, value: s.windSpeed })),\n2, // 2-unit square cells\n{ title: \"Wind speed\", unit: \"m/s\", colors: [\"#0000ff\", \"#00ff00\", \"#ff0000\"] },\n)\n```"
22
+ ],
23
+ "argsType": "PluginAnalysisHeatmapGridCell[]",
24
+ "resultType": "PluginAnalysisHeatmapsRenderResult"
25
+ },
26
+ {
27
+ "path": "analysis.heatmaps.renderSpaces",
28
+ "namespace": "analysis.heatmaps",
29
+ "summary": "Render a per-space heatmap — one flat colour per space's top face.",
30
+ "examplePrompts": [
31
+ "Color each room by its occupancy count",
32
+ "Show my energy simulation results as a heatmap per space",
33
+ "Paint the rooms red to blue by temperature\n\n# Example\n```ts\nconst spaces = await snaptrude.design.query.listSpaces()\nawait snaptrude.analysis.heatmaps.renderSpaces(\nspaces.map((space) => ({ space, value: occupancy[space] ?? 0 })),\n{ title: \"Occupancy\", unit: \"people\", min: 0, max: 50 },\n)\n```"
34
+ ],
35
+ "argsType": "PluginAnalysisHeatmapSpaceEntry[]",
36
+ "resultType": "PluginAnalysisHeatmapsRenderResult"
37
+ },
38
+ {
39
+ "path": "analysis.heatmaps.reset",
40
+ "namespace": "analysis.heatmaps",
41
+ "summary": "Clear the plugin heatmap from the scene.",
42
+ "examplePrompts": [
43
+ "Clear my custom heatmap",
44
+ "Remove the wind overlay from the model",
45
+ "Reset the plugin heatmap view\n\n# Example\n```ts\nawait snaptrude.analysis.heatmaps.reset()\n```"
46
+ ],
47
+ "argsType": null,
48
+ "resultType": "boolean"
49
+ },
50
+ {
51
+ "path": "analysis.illuminance.cancel",
52
+ "namespace": "analysis.illuminance",
53
+ "summary": "Cancel the in-flight illuminance run.",
54
+ "examplePrompts": [
55
+ "Cancel the illuminance analysis",
56
+ "Stop the running daylight computation",
57
+ "Abort the lux study\n\n# Example\n```ts\nawait snaptrude.analysis.illuminance.cancel()\n```"
58
+ ],
59
+ "argsType": null,
60
+ "resultType": "boolean"
61
+ },
62
+ {
63
+ "path": "analysis.illuminance.compute",
64
+ "namespace": "analysis.illuminance",
65
+ "summary": "Start a daylight-illuminance run for a date range.",
66
+ "examplePrompts": [
67
+ "Run a daylight illuminance analysis for December",
68
+ "Compute the lux levels inside the building for winter",
69
+ "How much daylight do the interior floors get?\n\n# Example\n```ts\nconst { success } = await snaptrude.analysis.illuminance.compute(\n\"2026-12-01\",\n\"2026-12-31\",\n)\n// poll until the heatmap is rendered\nlet job = await snaptrude.analysis.illuminance.get()\nwhile (job?.status === \"running\") {\nawait new Promise((r) => setTimeout(r, 5000))\njob = await snaptrude.analysis.illuminance.get()\n}\n```"
70
+ ],
71
+ "argsType": "string",
72
+ "resultType": "PluginAnalysisComputeResult"
73
+ },
74
+ {
75
+ "path": "analysis.illuminance.get",
76
+ "namespace": "analysis.illuminance",
77
+ "summary": "Get the state of the illuminance study.",
78
+ "examplePrompts": [
79
+ "Is the illuminance analysis done?",
80
+ "Check the status of the daylight lux run",
81
+ "What date range was the illuminance heatmap computed for?\n\n# Example\n```ts\nconst job = await snaptrude.analysis.illuminance.get()\nif (job?.status === \"active\") console.log(job.startDate, job.endDate)\n```"
82
+ ],
83
+ "argsType": null,
84
+ "resultType": "PluginAnalysisJobStateResult"
85
+ },
86
+ {
87
+ "path": "analysis.illuminance.reset",
88
+ "namespace": "analysis.illuminance",
89
+ "summary": "Clear the illuminance heatmap from the scene.",
90
+ "examplePrompts": [
91
+ "Clear the illuminance heatmap",
92
+ "Remove the daylight lux colours from the model",
93
+ "Reset the illuminance analysis view\n\n# Example\n```ts\nawait snaptrude.analysis.illuminance.reset()\n```"
94
+ ],
95
+ "argsType": null,
96
+ "resultType": "boolean"
97
+ },
98
+ {
99
+ "path": "analysis.shadows.disable",
100
+ "namespace": "analysis.shadows",
101
+ "summary": "Turn real-time sun shadows OFF.",
102
+ "examplePrompts": [
103
+ "Turn off shadows",
104
+ "Hide the sun shadows",
105
+ "Disable shadow rendering in the scene\n\n# Example\n```ts\nawait snaptrude.analysis.shadows.disable()\n```"
106
+ ],
107
+ "argsType": null,
108
+ "resultType": "boolean"
109
+ },
110
+ {
111
+ "path": "analysis.shadows.enable",
112
+ "namespace": "analysis.shadows",
113
+ "summary": "Turn real-time sun shadows ON, optionally at a specific date and time.",
114
+ "examplePrompts": [
115
+ "Turn on shadows",
116
+ "Show the shadows at 3pm on June 21st",
117
+ "Enable sun shadows for the summer solstice afternoon\n\n# Example\n```ts\nawait snaptrude.analysis.shadows.enable({ dateTime: \"2026-06-21T15:00\" })\n```"
118
+ ],
119
+ "argsType": "PluginAnalysisShadowsEnableOptions",
120
+ "resultType": "boolean"
121
+ },
122
+ {
123
+ "path": "analysis.shadows.getDateTime",
124
+ "namespace": "analysis.shadows",
125
+ "summary": "Get the sun's current date and time.",
126
+ "examplePrompts": [
127
+ "What date and time are the shadows set to?",
128
+ "Get the current sun position date",
129
+ "Which time of day is the shadow study showing?\n\n# Example\n```ts\nconst dateTime = await snaptrude.analysis.shadows.getDateTime()\n```"
130
+ ],
131
+ "argsType": null,
132
+ "resultType": "PluginAnalysisShadowsDateTimeResult"
133
+ },
134
+ {
135
+ "path": "analysis.shadows.isEnabled",
136
+ "namespace": "analysis.shadows",
137
+ "summary": "Whether real-time sun shadows are currently enabled.",
138
+ "examplePrompts": [
139
+ "Are shadows on?",
140
+ "Check whether sun shadows are enabled",
141
+ "Is the scene showing shadows right now?\n\n# Example\n```ts\nconst on = await snaptrude.analysis.shadows.isEnabled()\n```"
142
+ ],
143
+ "argsType": null,
144
+ "resultType": "boolean"
145
+ },
146
+ {
147
+ "path": "analysis.shadows.setDateTime",
148
+ "namespace": "analysis.shadows",
149
+ "summary": "Move the sun to a specific date and time.",
150
+ "examplePrompts": [
151
+ "Set the shadow time to 9:30 am on the winter solstice",
152
+ "Move the sun to noon on March 1st",
153
+ "Change the shadow study date to December 21\n\n# Example\n```ts\nconst applied = await snaptrude.analysis.shadows.setDateTime(\"2026-12-21T09:30\")\nconsole.log(applied) // \"2026-12-21T09:30\" (snapped to the half-hour grid)\n```"
154
+ ],
155
+ "argsType": "string",
156
+ "resultType": "PluginAnalysisShadowsDateTimeResult"
157
+ },
158
+ {
159
+ "path": "analysis.sunlightHours.cancel",
160
+ "namespace": "analysis.sunlightHours",
161
+ "summary": "Cancel the in-flight sunlight-hours run.",
162
+ "examplePrompts": [
163
+ "Cancel the sunlight analysis",
164
+ "Stop the running sunlight hours computation",
165
+ "Abort the sun study\n\n# Example\n```ts\nawait snaptrude.analysis.sunlightHours.cancel()\n```"
166
+ ],
167
+ "argsType": null,
168
+ "resultType": "boolean"
169
+ },
170
+ {
171
+ "path": "analysis.sunlightHours.compute",
172
+ "namespace": "analysis.sunlightHours",
173
+ "summary": "Start a direct-sunlight-hours run for a date range.",
174
+ "examplePrompts": [
175
+ "Run a sunlight hours analysis for June",
176
+ "Compute direct sunlight hours between March and September",
177
+ "How much sun does my building get over the summer?\n\n# Example\n```ts\nconst { success } = await snaptrude.analysis.sunlightHours.compute(\n\"2026-06-01\",\n\"2026-06-30\",\n)\n// poll until the heatmap is rendered\nlet job = await snaptrude.analysis.sunlightHours.get()\nwhile (job?.status === \"running\") {\nawait new Promise((r) => setTimeout(r, 5000))\njob = await snaptrude.analysis.sunlightHours.get()\n}\n```"
178
+ ],
179
+ "argsType": "string",
180
+ "resultType": "PluginAnalysisComputeResult"
181
+ },
182
+ {
183
+ "path": "analysis.sunlightHours.get",
184
+ "namespace": "analysis.sunlightHours",
185
+ "summary": "Get the state of the sunlight-hours study.",
186
+ "examplePrompts": [
187
+ "Is the sunlight analysis done?",
188
+ "Check the status of the sunlight hours run",
189
+ "What date range was the sunlight heatmap computed for?\n\n# Example\n```ts\nconst job = await snaptrude.analysis.sunlightHours.get()\nif (job?.status === \"active\") console.log(job.startDate, job.endDate)\n```"
190
+ ],
191
+ "argsType": null,
192
+ "resultType": "PluginAnalysisJobStateResult"
193
+ },
194
+ {
195
+ "path": "analysis.sunlightHours.reset",
196
+ "namespace": "analysis.sunlightHours",
197
+ "summary": "Clear the sunlight-hours heatmap from the scene.",
198
+ "examplePrompts": [
199
+ "Clear the sunlight heatmap",
200
+ "Remove the sun hours colours from the model",
201
+ "Reset the sunlight analysis view\n\n# Example\n```ts\nawait snaptrude.analysis.sunlightHours.reset()\n```"
202
+ ],
203
+ "argsType": null,
204
+ "resultType": "boolean"
205
+ },
206
+ {
207
+ "path": "analysis.sunpath.disable",
208
+ "namespace": "analysis.sunpath",
209
+ "summary": "Turn the sun-path diagram overlay OFF.",
210
+ "examplePrompts": [
211
+ "Hide the sun path diagram",
212
+ "Turn off the sunpath overlay",
213
+ "Remove the sun trajectory arcs from the scene\n\n# Example\n```ts\nawait snaptrude.analysis.sunpath.disable()\n```"
214
+ ],
215
+ "argsType": null,
216
+ "resultType": "boolean"
217
+ },
218
+ {
219
+ "path": "analysis.sunpath.enable",
220
+ "namespace": "analysis.sunpath",
221
+ "summary": "Turn the sun-path diagram overlay ON.",
222
+ "examplePrompts": [
223
+ "Show the sun path diagram",
224
+ "Turn on the sunpath overlay",
225
+ "Visualize the sun's trajectory over my building\n\n# Example\n```ts\nawait snaptrude.analysis.sunpath.enable()\nconst active = await snaptrude.analysis.sunpath.isActive() // true\n```"
226
+ ],
227
+ "argsType": null,
228
+ "resultType": "boolean"
229
+ },
230
+ {
231
+ "path": "analysis.sunpath.isActive",
232
+ "namespace": "analysis.sunpath",
233
+ "summary": "Whether the sun-path diagram overlay is currently active.",
234
+ "examplePrompts": [
235
+ "Is the sun path diagram on?",
236
+ "Check whether the sunpath overlay is active",
237
+ "Am I looking at the sun trajectory right now?\n\n# Example\n```ts\nif (!(await snaptrude.analysis.sunpath.isActive())) {\nawait snaptrude.analysis.sunpath.enable()\n}\n```"
238
+ ],
239
+ "argsType": null,
240
+ "resultType": "boolean"
241
+ },
2
242
  {
3
243
  "path": "core.buildings.copy",
4
244
  "namespace": "core.buildings",
@@ -107,6 +347,71 @@
107
347
  "argsType": "string",
108
348
  "resultType": "PluginCoreBuildingsUpdateResult"
109
349
  },
350
+ {
351
+ "path": "core.camera.getProjection",
352
+ "namespace": "core.camera",
353
+ "summary": "Read the camera's current projection: `\"perspective\"` (the default 3D view) or `\"orthographic\"`. In 2D (plan) mode this always reports `\"orthographic\"` — a plan is an orthographic projection.",
354
+ "examplePrompts": [
355
+ "Is the camera in perspective or orthographic?",
356
+ "What projection is the 3D view using?",
357
+ "Check whether perspective is on\n\n# Example\n```ts\nconst projection = await snaptrude.core.camera.getProjection()\nconsole.log(projection) // \"perspective\" | \"orthographic\"\n```"
358
+ ],
359
+ "argsType": null,
360
+ "resultType": "PluginCameraProjection"
361
+ },
362
+ {
363
+ "path": "core.camera.lookFrom",
364
+ "namespace": "core.camera",
365
+ "summary": "Point the camera: place its eye at `eye` looking toward `target` (world coordinates, internal `babylon` units). View-state only — not undoable.",
366
+ "examplePrompts": [
367
+ "Look at the model from above the north-east corner",
368
+ "Position the camera at (50, 30, 50) looking at the origin",
369
+ "Point the camera at the centre of the building from the side",
370
+ "Set the eye to this point and aim it at that point\n\n# Example\n```ts\nconst { vec3 } = snaptrude.core.math\nawait snaptrude.core.camera.lookFrom(vec3.new(50, 30, 50), vec3.new(0, 0, 0))\n```"
371
+ ],
372
+ "argsType": "Vec3Handle",
373
+ "resultType": "boolean"
374
+ },
375
+ {
376
+ "path": "core.camera.setMode",
377
+ "namespace": "core.camera",
378
+ "summary": "Toggle the modelling mode between `2d` (plan) and `3d`. Mirrors the canvas 2D/3D toggle: `3d` enters the isometric perspective view, `2d` drops to the orthographic plan of the active storey. View-state only — not undoable.",
379
+ "examplePrompts": [
380
+ "Switch to 3D view",
381
+ "Drop into 2D plan mode",
382
+ "Go back to 3D",
383
+ "Show the floor plan in 2D\n\n# Example\n```ts\nawait snaptrude.core.camera.setMode(\"3d\")\n```"
384
+ ],
385
+ "argsType": "PluginCameraMode",
386
+ "resultType": "boolean"
387
+ },
388
+ {
389
+ "path": "core.camera.setProjection",
390
+ "namespace": "core.camera",
391
+ "summary": "Switch the 3D camera between `\"perspective\"` and `\"orthographic\"` projection — the Perspective/Orthographic control in the Design tab's View Settings panel. Like {@linkcode PluginCameraApi.setMode}, this is a transient view-state change: not write-gated, not undoable.",
392
+ "examplePrompts": [
393
+ "Switch the camera to orthographic",
394
+ "Turn perspective off",
395
+ "Give me a perspective view of the model",
396
+ "Make the 3D view orthographic like an axonometric drawing\n\n# Example\n```ts\nawait snaptrude.core.camera.setProjection(\"orthographic\")\nconst projection = await snaptrude.core.camera.getProjection() // \"orthographic\"\n```"
397
+ ],
398
+ "argsType": "PluginCameraProjection",
399
+ "resultType": "boolean"
400
+ },
401
+ {
402
+ "path": "core.camera.setStandardView",
403
+ "namespace": "core.camera",
404
+ "summary": "Snap the camera to a standard view — the five orthographic elevations (`top` / `front` / `back` / `left` / `right`) or the 3D `iso` (isometric perspective) view. Mirrors the canvas view menu. View-state only — not undoable. The orthographic presets exit 2D mode first if needed.",
405
+ "examplePrompts": [
406
+ "Switch to the top view",
407
+ "Show me the front elevation",
408
+ "Go to the isometric view",
409
+ "Look at the model from the left",
410
+ "Give me a plan view from the top\n\n# Example\n```ts\nawait snaptrude.core.camera.setStandardView(\"top\")\n```"
411
+ ],
412
+ "argsType": "PluginStandardView",
413
+ "resultType": "boolean"
414
+ },
110
415
  {
111
416
  "path": "core.comment.create",
112
417
  "namespace": "core.comment",
@@ -133,6 +438,19 @@
133
438
  "argsType": "CommentHandle",
134
439
  "resultType": "boolean"
135
440
  },
441
+ {
442
+ "path": "core.comment.get",
443
+ "namespace": "core.comment",
444
+ "summary": "Read a comment's full detail — its text, author, pin location, resolved state, and reply thread. Comments are otherwise write-only; this is the read side. Pass a top-level comment handle or a reply handle (a reply has an empty `thread`). Returns `null` if the handle doesn't match a live comment.",
445
+ "examplePrompts": [
446
+ "Read the comment on this wall and tell me what it says",
447
+ "Who left this comment and where is it pinned?",
448
+ "Show me the full thread for this comment",
449
+ "Get the text and author of the selected comment\n\n# Example\n```ts\nconst [first] = await snaptrude.core.comment.list()\nconst details = await snaptrude.core.comment.get(first)\nconsole.log(details?.content, \"by\", details?.author?.name)\nconsole.log(`${details?.thread.length ?? 0} replies`)\n```"
450
+ ],
451
+ "argsType": "CommentHandle",
452
+ "resultType": "PluginCommentDetails | null"
453
+ },
136
454
  {
137
455
  "path": "core.comment.isResolved",
138
456
  "namespace": "core.comment",
@@ -172,6 +490,19 @@
172
490
  "argsType": "CommentHandle",
173
491
  "resultType": "boolean"
174
492
  },
493
+ {
494
+ "path": "core.comment.reply",
495
+ "namespace": "core.comment",
496
+ "summary": "Reply to a comment — posts a new comment threaded under `comment` (which must be a top-level comment, not itself a reply). Notifies the thread's participants, mirroring the sidebar Reply action.",
497
+ "examplePrompts": [
498
+ "Reply to this comment saying I fixed the wall height",
499
+ "Add a reply to the review note confirming it's done",
500
+ "Respond to the comment about the door with \"looks good now\"",
501
+ "Post a follow-up on the selected comment thread\n\n# Example\n```ts\nconst [thread] = await snaptrude.core.comment.list()\nconst reply = await snaptrude.core.comment.reply(thread, \"Fixed 👍\")\n```"
502
+ ],
503
+ "argsType": "CommentHandle",
504
+ "resultType": "CommentHandle"
505
+ },
175
506
  {
176
507
  "path": "core.comment.resolve",
177
508
  "namespace": "core.comment",
@@ -1783,6 +2114,46 @@
1783
2114
  "argsType": "string",
1784
2115
  "resultType": "PluginCoreGroupsUpdateResult"
1785
2116
  },
2117
+ {
2118
+ "path": "core.handles.beginScope",
2119
+ "namespace": "core.handles",
2120
+ "summary": "Open a mint-recording scope: every arena handle MINTED after this call (fresh mints only — identity-deduped re-registrations of pre-existing objects are not captured) is freed when the matching {@linkcode endScope} runs. Scopes nest, up to 64 deep — always pair begin/end in try/finally.",
2121
+ "examplePrompts": [],
2122
+ "argsType": null,
2123
+ "resultType": "ScopeToken"
2124
+ },
2125
+ {
2126
+ "path": "core.handles.endScope",
2127
+ "namespace": "core.handles",
2128
+ "summary": "Close a scope by its token and free every handle it recorded, except those listed in `retain`. Retained handles are promoted to the enclosing scope (if any), so nesting composes like block scopes. Closing is token-addressed: an out-of-order close (interleaved async tasks) frees only that scope's mints and leaves other open scopes intact. Always pair begin/end in try/finally so a thrown body cannot leak the scope.",
2129
+ "examplePrompts": [],
2130
+ "argsType": "ScopeToken",
2131
+ "resultType": "void"
2132
+ },
2133
+ {
2134
+ "path": "core.handles.release",
2135
+ "namespace": "core.handles",
2136
+ "summary": "Free arena handles in bulk. Unknown, foreign, or already-released ids are silent no-ops — there is no per-id result and no count, so responses can never be used as an existence oracle.",
2137
+ "examplePrompts": [],
2138
+ "argsType": "ReadonlyArray<AnyArenaHandle>",
2139
+ "resultType": "void"
2140
+ },
2141
+ {
2142
+ "path": "core.handles.releaseAll",
2143
+ "namespace": "core.handles",
2144
+ "summary": "Free every live arena handle of one kind, or ALL arena handles when the kind is omitted. Useful at batch boundaries — e.g. a poll loop that mints a fresh footprint contour per tick.",
2145
+ "examplePrompts": [],
2146
+ "argsType": "ArenaKind",
2147
+ "resultType": "void"
2148
+ },
2149
+ {
2150
+ "path": "core.handles.stats",
2151
+ "namespace": "core.handles",
2152
+ "summary": "Live handle-registry statistics for the calling plugin, plus the host page's JS heap usage (when the browser exposes it). Diagnostic surface for verifying that releases actually shrink host memory.",
2153
+ "examplePrompts": [],
2154
+ "argsType": null,
2155
+ "resultType": "PluginHandlesStatsResult"
2156
+ },
1786
2157
  {
1787
2158
  "path": "core.history.redo",
1788
2159
  "namespace": "core.history",
@@ -1811,112 +2182,551 @@
1811
2182
  "resultType": "PluginHistoryStepResult"
1812
2183
  },
1813
2184
  {
1814
- "path": "core.layers.get",
1815
- "namespace": "core.layers",
1816
- "summary": "Get a single drawing layer by id.",
2185
+ "path": "core.io.export.model",
2186
+ "namespace": "core.io.export",
2187
+ "summary": "Export the model to a 3D file and return its bytes as base64.",
1817
2188
  "examplePrompts": [
1818
- "Get the drawing layer with id ly_5",
1819
- "Is layer ly_5 hidden or locked?",
1820
- "Look up a single drawing layer by its id\n\n# Example\n```ts\nconst layer = await snaptrude.core.layers.get(\"ly_5\")\nif (layer) console.log(layer.name, layer.hidden, layer.locked)\n```"
2189
+ "Export the model as a GLB",
2190
+ "Give me the whole scene as an OBJ file",
2191
+ "Export just my selection to GLB",
2192
+ "Download the model as an FBX file",
2193
+ "Export the scene to 3DS for 3ds Max\n\n# Example\n```ts\nconst file = await snaptrude.core.io.export.model(\"glb\")\n// decode base64 → bytes and save/download in the plugin UI\nconst bytes = Uint8Array.from(atob(file.dataBase64), (c) => c.charCodeAt(0))\nconst blob = new Blob([bytes], { type: file.mimeType })\n// ...offer blob for download as file.fileName\n\n// Only the current selection, as OBJ text:\nconst obj = await snaptrude.core.io.export.model(\"obj\", \"selection\")\nconst text = atob(obj.dataBase64)\n```"
1821
2194
  ],
1822
- "argsType": "string",
1823
- "resultType": "PluginCoreLayersGetResult"
2195
+ "argsType": "ExportModelFormat",
2196
+ "resultType": "ExportedFile"
1824
2197
  },
1825
2198
  {
1826
- "path": "core.layers.getActive",
1827
- "namespace": "core.layers",
1828
- "summary": "Get the active drawing layer of a storey.",
2199
+ "path": "core.io.import.cadJson",
2200
+ "namespace": "core.io.import",
2201
+ "summary": "Sketch a CAD underlay from **already-parsed CAD JSON** — synchronous, with no server round-trip. Use this when you hold parsed CAD data (e.g. produced by your own converter); use {@link PluginCoreIoImportApi.dwg} for raw `.dwg` files.",
1829
2202
  "examplePrompts": [
1830
- "Which drawing layer is active on this storey?",
1831
- "Get the current layer on storey st_2",
1832
- "What layer am I drawing on?\n\n# Example\n```ts\nconst active = await snaptrude.core.layers.getActive(\"st_2\")\nif (active) console.log(active.name)\n```"
2203
+ "Sketch this parsed CAD JSON onto the active storey",
2204
+ "Draw these CAD curves as an underlay on storey 2",
2205
+ "Create a CAD sketch from this geometry data",
2206
+ "Import my converted CAD JSON onto the ground floor\n\n# Example\n```ts\nconst cad = await snaptrude.core.io.import.cadJson(\n{ unit: \"mm\", geometry: [{ type: \"line\", layer: \"WALLS\", ... }] },\n1,\n)\n```"
2207
+ ],
2208
+ "argsType": "CadJsonInput",
2209
+ "resultType": "UnderlayHandle"
2210
+ },
2211
+ {
2212
+ "path": "core.io.import.dwg",
2213
+ "namespace": "core.io.import",
2214
+ "summary": "Import a **DWG** CAD drawing as a scene underlay. `.dwg` only (no DXF).",
2215
+ "examplePrompts": [
2216
+ "Import this DWG floor plan onto storey 1",
2217
+ "Bring in a CAD drawing as an underlay and tell me when it's ready",
2218
+ "Start importing this CAD file onto the ground floor\n\n# Example\n```ts\nconst job = await snaptrude.core.io.import.dwg(\"https://example.com/plan.dwg\", 1)\n// Poll until the server-side conversion finishes — always with a timeout\n// (a UI-cancelled import stays \"processing\" forever).\nconst deadline = Date.now() + 5 * 60_000\nwhile (!(await snaptrude.core.io.job.isComplete(job))) {\nif (Date.now() > deadline) throw new Error(\"DWG import timed out\")\nawait new Promise((r) => setTimeout(r, 2000))\n}\n// The DWG lands as a CAD underlay. CAD scaling isn't supported; manage it\n// (list / fade / delete) via core.io.underlay.*.\nconst cad = await snaptrude.core.io.job.getResult(job)\nif (cad) console.log(\"DWG imported as CAD underlay:\", cad)\n```"
1833
2219
  ],
1834
2220
  "argsType": "string",
1835
- "resultType": "PluginCoreLayersGetActiveResult"
2221
+ "resultType": "ImportJobHandle"
1836
2222
  },
1837
2223
  {
1838
- "path": "core.layers.list",
1839
- "namespace": "core.layers",
1840
- "summary": "List the drawing layers of a storey.",
2224
+ "path": "core.io.import.image",
2225
+ "namespace": "core.io.import",
2226
+ "summary": "Import a raster image as a scene **underlay** — a flat, textured reference plane placed on a storey that you can trace over.",
1841
2227
  "examplePrompts": [
1842
- "List the drawing layers on this storey",
1843
- "Show all the PDF underlays on storey st_2",
1844
- "What CAD layers are on the ground floor?\n\n# Example\n```ts\nconst { layers } = await snaptrude.core.layers.list(\"st_2\")\nfor (const l of layers) console.log(l.name, l.layerType, l.hidden)\n```"
2228
+ "Import this floor plan image onto the ground floor to trace over",
2229
+ "Drop this survey PNG in as a reference underlay at 30% opacity",
2230
+ "Add a site plan image on storey 2",
2231
+ "Bring in a sketch to trace, faded to half opacity\n\n# Example\n```ts\n// Place a floor plan on storey 1, then calibrate it to a real-world size.\nconst plan = await snaptrude.core.io.import.image(\n\"https://example.com/floorplan.png\",\n1, // storey\nundefined, // scale\n0.4, // opacity\n\"Ground floor plan\",\n)\n// Make the plan's longest side exactly 40 project-units:\nawait snaptrude.core.io.underlay.setScale(plan, { planSize: 40 })\n```"
1845
2232
  ],
1846
2233
  "argsType": "string",
1847
- "resultType": "PluginCoreLayersListResult"
2234
+ "resultType": "UnderlayHandle"
1848
2235
  },
1849
2236
  {
1850
- "path": "core.layers.setActive",
1851
- "namespace": "core.layers",
1852
- "summary": "Make a drawing layer the active layer of its storey.",
2237
+ "path": "core.io.import.model",
2238
+ "namespace": "core.io.import",
2239
+ "summary": "Import a **3D model** file and place it in the scene as a component.",
1853
2240
  "examplePrompts": [
1854
- "Draw on layer ly_5",
1855
- "Make this the active layer",
1856
- "Switch the active layer to the CAD underlay\n\n# Example\n```ts\nawait snaptrude.core.layers.setActive(\"ly_5\")\n```"
2241
+ "Import this SketchUp model onto storey 1",
2242
+ "Bring in this OBJ file and place it at the origin",
2243
+ "Add this 3D model to the ground floor\n\n# Example\n```ts\nconst model = await snaptrude.core.io.import.model(\n\"https://example.com/tree.skp\",\n1, // storey\n\"skp\",\n)\n```"
1857
2244
  ],
1858
2245
  "argsType": "string",
1859
- "resultType": "PluginCoreLayersSetActiveResult"
2246
+ "resultType": "ComponentHandle"
1860
2247
  },
1861
2248
  {
1862
- "path": "core.layers.update",
1863
- "namespace": "core.layers",
1864
- "summary": "Update a drawing layer's visibility.",
2249
+ "path": "core.io.import.pdf",
2250
+ "namespace": "core.io.import",
2251
+ "summary": "Import one page of a PDF as a scene **underlay** (a traceable reference plane).",
1865
2252
  "examplePrompts": [
1866
- "Hide the PDF underlay layer",
1867
- "Show the CAD layer again",
1868
- "Hide layer ly_5\n\n# Example\n```ts\nconst layer = await snaptrude.core.layers.update(\"ly_5\", true)\n```"
2253
+ "Import page 1 of this PDF floor plan onto storey 1",
2254
+ "Bring in the second page of this PDF as an underlay at 1:50",
2255
+ "Add this PDF plan to the ground floor to trace over",
2256
+ "Place page 3 of the drawing set on storey 3\n\n# Example\n```ts\nconst sheet = await snaptrude.core.io.import.pdf(\n\"https://example.com/plans.pdf\",\n1, // storey\n2, // page\n\"1:100\", // drawing scale\n)\n```"
1869
2257
  ],
1870
2258
  "argsType": "string",
1871
- "resultType": "PluginCoreLayersUpdateResult"
2259
+ "resultType": "UnderlayHandle"
1872
2260
  },
1873
2261
  {
1874
- "path": "core.math.quat.components",
1875
- "namespace": "core.math.quat",
1876
- "summary": "Read the primitive `{ x, y, z, w }` components of a quaternion handle.",
1877
- "examplePrompts": [],
1878
- "argsType": "QuatHandle",
1879
- "resultType": "QuatComponents"
2262
+ "path": "core.io.import.terrain",
2263
+ "namespace": "core.io.import",
2264
+ "summary": "Import **site terrain** for a location Mapbox topography (elevation + satellite/streets imagery, optional neighborhood buildings and parcels).",
2265
+ "examplePrompts": [
2266
+ "Import the site terrain for this location, about 500m across",
2267
+ "Load the topography at 40.7128, -74.0060 for a 300 by 300 meter site",
2268
+ "Bring in satellite terrain for the site with the surrounding buildings",
2269
+ "Add site elevation for a 1km by 1km area at these coordinates\n\n# Example\n```ts\n// 300m × 300m site with elevation + satellite imagery.\nconst terrain = await snaptrude.core.io.import.terrain(\n40.7128, // lat\n-74.006, // lng\n300, // width (metres)\n300, // length (metres)\ntrue, // elevation\ntrue, // satellite\n)\n```"
2270
+ ],
2271
+ "argsType": "number",
2272
+ "resultType": "TerrainHandle"
1880
2273
  },
1881
2274
  {
1882
- "path": "core.math.quat.conjugate",
1883
- "namespace": "core.math.quat",
1884
- "summary": "Compute the conjugate of a quaternion (negated vector part).",
1885
- "examplePrompts": [],
1886
- "argsType": "QuatHandle",
1887
- "resultType": "QuatHandle"
2275
+ "path": "core.io.job.getError",
2276
+ "namespace": "core.io.job",
2277
+ "summary": "The failure message if the job's status is `\"failed\"`; otherwise `null`.",
2278
+ "examplePrompts": [
2279
+ "Why did my DWG import fail?",
2280
+ "What went wrong with the CAD import?",
2281
+ "Show the error from the failed import job",
2282
+ "Did the import error out, and why?\n\n# Example\n```ts\nconst job = await snaptrude.core.io.import.dwg(url, 1)\nif ((await snaptrude.core.io.job.getStatus(job)) === \"failed\") {\nconsole.error(await snaptrude.core.io.job.getError(job))\n}\n```"
2283
+ ],
2284
+ "argsType": "ImportJobHandle",
2285
+ "resultType": "string | null"
1888
2286
  },
1889
2287
  {
1890
- "path": "core.math.quat.dot",
1891
- "namespace": "core.math.quat",
1892
- "summary": "Compute the dot product of two quaternions.",
1893
- "examplePrompts": [],
1894
- "argsType": "QuatHandle",
1895
- "resultType": "number"
2288
+ "path": "core.io.job.getResult",
2289
+ "namespace": "core.io.job",
2290
+ "summary": "The imported result once the job is complete the placed {@linkcode UnderlayHandle}. Returns `null` while the job is still pending/processing or if it failed (check {@link PluginCoreIoJobApi.getError}).",
2291
+ "examplePrompts": [
2292
+ "Get the underlay from my finished DWG import",
2293
+ "Give me the result of the CAD import job",
2294
+ "Fetch the imported CAD sketch once it's ready",
2295
+ "Return the handle for the completed import\n\n# Example\n```ts\nconst job = await snaptrude.core.io.import.dwg(url, 1)\nconst deadline = Date.now() + 5 * 60_000\nwhile (!(await snaptrude.core.io.job.isComplete(job))) {\nif (Date.now() > deadline) throw new Error(\"DWG import timed out\")\nawait new Promise((r) => setTimeout(r, 2000))\n}\n// DWG results are CAD underlays (CAD scaling isn't supported); manage them\n// via core.io.underlay.* (list / setOpacity / delete).\nconst cad = await snaptrude.core.io.job.getResult(job)\nif (cad) console.log(\"import complete:\", cad)\n```"
2296
+ ],
2297
+ "argsType": "ImportJobHandle",
2298
+ "resultType": "UnderlayHandle | null"
1896
2299
  },
1897
2300
  {
1898
- "path": "core.math.quat.equals",
1899
- "namespace": "core.math.quat",
1900
- "summary": "Test whether two quaternions have exactly equal components.",
1901
- "examplePrompts": [],
1902
- "argsType": "QuatHandle",
1903
- "resultType": "boolean"
2301
+ "path": "core.io.job.getStatus",
2302
+ "namespace": "core.io.job",
2303
+ "summary": "Read a job's current status: `\"pending\"` (queued), `\"processing\"` (running), `\"complete\"` (result ready), or `\"failed\"`.",
2304
+ "examplePrompts": [
2305
+ "What's the status of my DWG import?",
2306
+ "Is the CAD import still processing?",
2307
+ "Check where the import job is up to",
2308
+ "Did the import job fail?\n\n# Example\n```ts\nconst job = await snaptrude.core.io.import.dwg(url, 1)\nconsole.log(await snaptrude.core.io.job.getStatus(job)) // \"processing\"\n```"
2309
+ ],
2310
+ "argsType": "ImportJobHandle",
2311
+ "resultType": "ImportJobStatus"
1904
2312
  },
1905
2313
  {
1906
- "path": "core.math.quat.equalsApprox",
1907
- "namespace": "core.math.quat",
1908
- "summary": "Test whether two quaternions are equal within a tolerance `epsilon` (default `1e-6`).",
1909
- "examplePrompts": [],
1910
- "argsType": "QuatHandle",
2314
+ "path": "core.io.job.isComplete",
2315
+ "namespace": "core.io.job",
2316
+ "summary": "Whether the job has finished successfully (status is `\"complete\"` and a result is ready). Returns `false` while pending/processing and on failure.",
2317
+ "examplePrompts": [
2318
+ "Is the DWG import done yet?",
2319
+ "Has the CAD import finished?",
2320
+ "Tell me when the import job completes",
2321
+ "Is my import ready?\n\n# Example\n```ts\nconst job = await snaptrude.core.io.import.dwg(url, 1)\nconst deadline = Date.now() + 5 * 60_000 // cap the poll — see getStatus limitation\nwhile (!(await snaptrude.core.io.job.isComplete(job))) {\nif (Date.now() > deadline) throw new Error(\"DWG import timed out\")\nawait new Promise((r) => setTimeout(r, 2000))\n}\n```"
2322
+ ],
2323
+ "argsType": "ImportJobHandle",
1911
2324
  "resultType": "boolean"
1912
2325
  },
1913
2326
  {
1914
- "path": "core.math.quat.fromAxisAngle",
1915
- "namespace": "core.math.quat",
1916
- "summary": "Build a quaternion from a rotation axis and an angle in radians.",
1917
- "examplePrompts": [],
1918
- "argsType": "Vec3Handle",
1919
- "resultType": "QuatHandle"
2327
+ "path": "core.io.query.getPdfPageCount",
2328
+ "namespace": "core.io.query",
2329
+ "summary": "Count the pages of a PDF without importing it. `null` if the source can't be read as a PDF.",
2330
+ "examplePrompts": [
2331
+ "How many pages does this PDF have?",
2332
+ "Count the pages in the drawing set before importing",
2333
+ "Get the PDF page count",
2334
+ "Is this a multi-page PDF, and how many?\n\n# Example\n```ts\nconst pages = await snaptrude.core.io.query.getPdfPageCount(url)\nfor (let p = 1; p <= (pages ?? 0); p++) {\nawait snaptrude.core.io.import.pdf(url, p, p) // one page per storey\n}\n```"
2335
+ ],
2336
+ "argsType": "string",
2337
+ "resultType": "number | null"
2338
+ },
2339
+ {
2340
+ "path": "core.io.query.listCadLayers",
2341
+ "namespace": "core.io.query",
2342
+ "summary": "List the distinct CAD layer names tagged on a parsed CAD JSON's entities. Read-only inspection: imports always bring in **every** layer (there is no layer filter on {@link core.io.import.dwg} / {@link core.io.import.cadJson}) — use the names to decide whether to import at all, or what to tell the user.",
2343
+ "examplePrompts": [
2344
+ "What CAD layers are in this drawing?",
2345
+ "List the layers before importing the CAD",
2346
+ "Show the DWG layer names so I can pick which to import",
2347
+ "Enumerate the CAD JSON layers\n\n# Example\n```ts\nconst layers = await snaptrude.core.io.query.listCadLayers(cad)\nif (layers.some((l) => l.toUpperCase().includes(\"WALL\"))) {\nawait snaptrude.core.io.import.cadJson(cad, 1) // all layers import together\n}\n```"
2348
+ ],
2349
+ "argsType": "CadJsonInput",
2350
+ "resultType": "string[]"
2351
+ },
2352
+ {
2353
+ "path": "core.io.terrain.delete",
2354
+ "namespace": "core.io.terrain",
2355
+ "summary": "Delete the site terrain. Undoable.",
2356
+ "examplePrompts": [
2357
+ "Delete the site terrain",
2358
+ "Remove the topography",
2359
+ "Clear the imported site",
2360
+ "Get rid of the terrain"
2361
+ ],
2362
+ "argsType": null,
2363
+ "resultType": "void"
2364
+ },
2365
+ {
2366
+ "path": "core.io.terrain.disableElevation",
2367
+ "namespace": "core.io.terrain",
2368
+ "summary": "Turn terrain elevation OFF — flatten to a plane. Undoable.",
2369
+ "examplePrompts": [
2370
+ "Flatten the terrain",
2371
+ "Turn off site elevation",
2372
+ "Disable the heightmap",
2373
+ "Make the terrain flat"
2374
+ ],
2375
+ "argsType": null,
2376
+ "resultType": "void"
2377
+ },
2378
+ {
2379
+ "path": "core.io.terrain.disableSatellite",
2380
+ "namespace": "core.io.terrain",
2381
+ "summary": "Turn satellite imagery OFF. Undoable.",
2382
+ "examplePrompts": [
2383
+ "Hide the satellite imagery",
2384
+ "Turn off the aerial texture",
2385
+ "Disable satellite on the site",
2386
+ "Remove the satellite drape"
2387
+ ],
2388
+ "argsType": null,
2389
+ "resultType": "void"
2390
+ },
2391
+ {
2392
+ "path": "core.io.terrain.enableElevation",
2393
+ "namespace": "core.io.terrain",
2394
+ "summary": "Turn terrain elevation (DEM height) ON — a real 3D topography surface. Undoable.",
2395
+ "examplePrompts": [
2396
+ "Turn on terrain elevation",
2397
+ "Enable the site heightmap",
2398
+ "Make the terrain 3D",
2399
+ "Show the topography relief"
2400
+ ],
2401
+ "argsType": null,
2402
+ "resultType": "void"
2403
+ },
2404
+ {
2405
+ "path": "core.io.terrain.enableSatellite",
2406
+ "namespace": "core.io.terrain",
2407
+ "summary": "Turn satellite imagery ON. Undoable.",
2408
+ "examplePrompts": [
2409
+ "Show satellite imagery on the site",
2410
+ "Enable the satellite texture",
2411
+ "Turn on aerial imagery",
2412
+ "Drape satellite over the terrain"
2413
+ ],
2414
+ "argsType": null,
2415
+ "resultType": "void"
2416
+ },
2417
+ {
2418
+ "path": "core.io.terrain.exists",
2419
+ "namespace": "core.io.terrain",
2420
+ "summary": "Whether the project has a site terrain.",
2421
+ "examplePrompts": [
2422
+ "Does this project have site terrain?",
2423
+ "Is there a terrain imported?",
2424
+ "Check if the site topography exists",
2425
+ "Has a terrain been added yet?\n\n# Example\n```ts\nif (!(await snaptrude.core.io.terrain.exists())) {\nawait snaptrude.core.io.import.terrain(40.7128, -74.006, 300, 300)\n}\n```"
2426
+ ],
2427
+ "argsType": null,
2428
+ "resultType": "boolean"
2429
+ },
2430
+ {
2431
+ "path": "core.io.terrain.get",
2432
+ "namespace": "core.io.terrain",
2433
+ "summary": "Resolve the project's terrain handle, or `null` if there is none. The same handle {@link core.io.import.terrain} returns — use it to obtain the handle without re-importing.",
2434
+ "examplePrompts": [
2435
+ "Get the terrain handle",
2436
+ "Give me the site terrain",
2437
+ "Fetch the current terrain",
2438
+ "Return the topography handle if it exists"
2439
+ ],
2440
+ "argsType": null,
2441
+ "resultType": "TerrainHandle | null"
2442
+ },
2443
+ {
2444
+ "path": "core.io.terrain.getDatum",
2445
+ "namespace": "core.io.terrain",
2446
+ "summary": "Read the terrain's current vertical position (world Y, internal units). `null` if there is no terrain. Import places the terrain so its highest point sits at `y = 0`, so a never-shifted terrain reads a negative baseline, not `0`; each {@link PluginCoreIoTerrainApi.setDatum} shift moves this value.",
2447
+ "examplePrompts": [
2448
+ "What's the terrain's datum?",
2449
+ "Read the current site elevation reference",
2450
+ "Get the terrain vertical offset",
2451
+ "How far has the datum been shifted?"
2452
+ ],
2453
+ "argsType": null,
2454
+ "resultType": "number | null"
2455
+ },
2456
+ {
2457
+ "path": "core.io.terrain.getOpacity",
2458
+ "namespace": "core.io.terrain",
2459
+ "summary": "Read the terrain opacity, `0`..`1`, or `null` if no terrain.",
2460
+ "examplePrompts": [],
2461
+ "argsType": null,
2462
+ "resultType": "number | null"
2463
+ },
2464
+ {
2465
+ "path": "core.io.terrain.getReport",
2466
+ "namespace": "core.io.terrain",
2467
+ "summary": "The terrain cut/fill earthwork report — cut, fill, and net volumes — or `null` if there is no terrain.",
2468
+ "examplePrompts": [
2469
+ "What are the cut and fill volumes for the site?",
2470
+ "Get the terrain earthwork report",
2471
+ "How much cut and fill does the grading need?",
2472
+ "Show the net volume of the terrain edits\n\n# Example\n```ts\nconst r = await snaptrude.core.io.terrain.getReport()\nif (r) console.log(`cut ${r.cutVolume}, fill ${r.fillVolume}, net ${r.netVolume}`)\n```"
2473
+ ],
2474
+ "argsType": null,
2475
+ "resultType": "TerrainReport | null"
2476
+ },
2477
+ {
2478
+ "path": "core.io.terrain.isElevationEnabled",
2479
+ "namespace": "core.io.terrain",
2480
+ "summary": "Whether terrain elevation (DEM height) is on. `null` if no terrain.",
2481
+ "examplePrompts": [],
2482
+ "argsType": null,
2483
+ "resultType": "boolean | null"
2484
+ },
2485
+ {
2486
+ "path": "core.io.terrain.isSatelliteEnabled",
2487
+ "namespace": "core.io.terrain",
2488
+ "summary": "Whether satellite imagery is draped on the terrain. `null` if no terrain.",
2489
+ "examplePrompts": [],
2490
+ "argsType": null,
2491
+ "resultType": "boolean | null"
2492
+ },
2493
+ {
2494
+ "path": "core.io.terrain.setDatum",
2495
+ "namespace": "core.io.terrain",
2496
+ "summary": "Shift the terrain's **datum** — move the whole terrain vertically DOWN by `offset` (internal units) from its current position; pass a negative value to raise it. Undoable.",
2497
+ "examplePrompts": [
2498
+ "Shift the terrain datum down by 12",
2499
+ "Lower the site terrain by 10",
2500
+ "Raise the terrain a little",
2501
+ "Nudge the terrain datum down\n\n# Example\n```ts\nawait snaptrude.core.io.terrain.setDatum(12) // shift terrain down by 12 (relative)\n```"
2502
+ ],
2503
+ "argsType": "number",
2504
+ "resultType": "void"
2505
+ },
2506
+ {
2507
+ "path": "core.io.terrain.setOpacity",
2508
+ "namespace": "core.io.terrain",
2509
+ "summary": "Set the terrain opacity (`0` transparent .. `1` opaque). Undoable.",
2510
+ "examplePrompts": [
2511
+ "Fade the terrain to 50%",
2512
+ "Make the site semi-transparent",
2513
+ "Set terrain opacity to 0.3",
2514
+ "Dim the topography\n\n# Example\n```ts\nawait snaptrude.core.io.terrain.setOpacity(0.5)\n```"
2515
+ ],
2516
+ "argsType": "number",
2517
+ "resultType": "void"
2518
+ },
2519
+ {
2520
+ "path": "core.io.underlay.delete",
2521
+ "namespace": "core.io.underlay",
2522
+ "summary": "Delete an underlay from the scene (and its backend record). Applies to image, PDF, and CAD underlays.",
2523
+ "examplePrompts": [
2524
+ "Delete this floor plan underlay",
2525
+ "Remove the imported PDF from the scene",
2526
+ "Get rid of the CAD sketch I traced over",
2527
+ "Clear the reference image off storey 1\n\n# Example\n```ts\nconst [first] = await snaptrude.core.io.underlay.list(1)\nif (first) await snaptrude.core.io.underlay.delete(first)\n```"
2528
+ ],
2529
+ "argsType": "UnderlayHandle",
2530
+ "resultType": "void"
2531
+ },
2532
+ {
2533
+ "path": "core.io.underlay.getBounds",
2534
+ "namespace": "core.io.underlay",
2535
+ "summary": "Read an underlay's world-space bounding box (image, PDF, or CAD). `null` if the underlay no longer resolves or has no measurable mesh. Useful for fitting drawn geometry to a reference, or computing a plan size before scaling.",
2536
+ "examplePrompts": [
2537
+ "How big is this floor plan in the scene?",
2538
+ "Get the bounding box of the underlay",
2539
+ "What's the extent of the imported PDF?",
2540
+ "Measure the CAD sketch's size\n\n# Example\n```ts\nconst bb = await snaptrude.core.io.underlay.getBounds(plan)\nif (bb) console.log(`width ${bb.max.x - bb.min.x}`)\n```"
2541
+ ],
2542
+ "argsType": "UnderlayHandle",
2543
+ "resultType": "BBoxComponents | null"
2544
+ },
2545
+ {
2546
+ "path": "core.io.underlay.getOpacity",
2547
+ "namespace": "core.io.underlay",
2548
+ "summary": "Read an underlay's opacity (`0`..`1`), or `null` if it has no material.",
2549
+ "examplePrompts": [
2550
+ "How transparent is this underlay?",
2551
+ "Get the opacity of the floor plan",
2552
+ "What's the fade level on the reference image?",
2553
+ "Read the underlay's opacity\n\n# Example\n```ts\nconst o = await snaptrude.core.io.underlay.getOpacity(plan)\n```"
2554
+ ],
2555
+ "argsType": "UnderlayHandle",
2556
+ "resultType": "number | null"
2557
+ },
2558
+ {
2559
+ "path": "core.io.underlay.getScale",
2560
+ "namespace": "core.io.underlay",
2561
+ "summary": "Read an underlay's scale. Works for **image and PDF** underlays. Returns `null` for CAD (scaling not supported) or if the handle no longer resolves.",
2562
+ "examplePrompts": [
2563
+ "What scale is this floor plan set to?",
2564
+ "Get the current and original scale of the underlay",
2565
+ "How much has this image been scaled since import?",
2566
+ "Read the scale factor of the reference plan\n\n# Example\n```ts\nconst s = await snaptrude.core.io.underlay.getScale(plan)\nif (s) console.log(`scale ${s.scaleFactor} (was ${s.initialScaleFactor})`)\n```"
2567
+ ],
2568
+ "argsType": "UnderlayHandle",
2569
+ "resultType": "{ scaleFactor: number; initialScaleFactor: number } | null"
2570
+ },
2571
+ {
2572
+ "path": "core.io.underlay.list",
2573
+ "namespace": "core.io.underlay",
2574
+ "summary": "List the underlays in the scene, optionally limited to one storey.",
2575
+ "examplePrompts": [
2576
+ "List all the reference underlays in the model",
2577
+ "What underlays are on the ground floor?",
2578
+ "Show every imported floor plan and PDF",
2579
+ "How many trace-over images are on storey 2?\n\n# Example\n```ts\nconst underlays = await snaptrude.core.io.underlay.list(1)\nconsole.log(`${underlays.length} underlays on storey 1`)\n```"
2580
+ ],
2581
+ "argsType": "number",
2582
+ "resultType": "UnderlayHandle[]"
2583
+ },
2584
+ {
2585
+ "path": "core.io.underlay.resetScale",
2586
+ "namespace": "core.io.underlay",
2587
+ "summary": "Reset an underlay's scale back to its import-time size (image or PDF; CAD scaling is not supported — throws). Equivalent to `setScale(underlay, 1)`.",
2588
+ "examplePrompts": [
2589
+ "Reset this floor plan's scale to how it was imported",
2590
+ "Undo the scaling on the underlay",
2591
+ "Put the reference image back to its original size",
2592
+ "Restore the plan's default scale\n\n# Example\n```ts\nawait snaptrude.core.io.underlay.resetScale(plan)\n```"
2593
+ ],
2594
+ "argsType": "UnderlayHandle",
2595
+ "resultType": "{ scaleFactor: number }"
2596
+ },
2597
+ {
2598
+ "path": "core.io.underlay.setOpacity",
2599
+ "namespace": "core.io.underlay",
2600
+ "summary": "Set an underlay's opacity (`0` = transparent .. `1` = opaque). Undoable. The engine keeps underlays faintly visible: values below `0.01` clamp to `0.01`, so `setOpacity(u, 0)` reads back as `0.01`, not `0`.",
2601
+ "examplePrompts": [
2602
+ "Fade this floor plan to 30% so I can see through it",
2603
+ "Make the underlay half transparent",
2604
+ "Set the reference image opacity to 0.2",
2605
+ "Dim the trace-over plan\n\n# Example\n```ts\nawait snaptrude.core.io.underlay.setOpacity(plan, 0.3)\n```"
2606
+ ],
2607
+ "argsType": "UnderlayHandle",
2608
+ "resultType": "void"
2609
+ },
2610
+ {
2611
+ "path": "core.io.underlay.setScale",
2612
+ "namespace": "core.io.underlay",
2613
+ "summary": "Set an underlay's scale — the **calibration** step after import. Works for **image and PDF** underlays (CAD scaling is not supported — throws).",
2614
+ "examplePrompts": [
2615
+ "Scale this floor plan so it's 50 meters across",
2616
+ "Set the plan size to 30m — it's imported too small",
2617
+ "Make the reference image twice its imported size",
2618
+ "Calibrate the PDF: the site is 120 meters long\n\n# Example\n```ts\n// Absolute factor — set the underlay to 2× its imported size:\nawait snaptrude.core.io.underlay.setScale(plan, 2)\n\n// Fit to a real-world size — make the plan's longest side 50 project-units:\nawait snaptrude.core.io.underlay.setScale(plan, { planSize: 50 })\n```"
2619
+ ],
2620
+ "argsType": "UnderlayHandle",
2621
+ "resultType": "{ scaleFactor: number }"
2622
+ },
2623
+ {
2624
+ "path": "core.layers.get",
2625
+ "namespace": "core.layers",
2626
+ "summary": "Get a single drawing layer by id.",
2627
+ "examplePrompts": [
2628
+ "Get the drawing layer with id ly_5",
2629
+ "Is layer ly_5 hidden or locked?",
2630
+ "Look up a single drawing layer by its id\n\n# Example\n```ts\nconst layer = await snaptrude.core.layers.get(\"ly_5\")\nif (layer) console.log(layer.name, layer.hidden, layer.locked)\n```"
2631
+ ],
2632
+ "argsType": "string",
2633
+ "resultType": "PluginCoreLayersGetResult"
2634
+ },
2635
+ {
2636
+ "path": "core.layers.getActive",
2637
+ "namespace": "core.layers",
2638
+ "summary": "Get the active drawing layer of a storey.",
2639
+ "examplePrompts": [
2640
+ "Which drawing layer is active on this storey?",
2641
+ "Get the current layer on storey st_2",
2642
+ "What layer am I drawing on?\n\n# Example\n```ts\nconst active = await snaptrude.core.layers.getActive(\"st_2\")\nif (active) console.log(active.name)\n```"
2643
+ ],
2644
+ "argsType": "string",
2645
+ "resultType": "PluginCoreLayersGetActiveResult"
2646
+ },
2647
+ {
2648
+ "path": "core.layers.list",
2649
+ "namespace": "core.layers",
2650
+ "summary": "List the drawing layers of a storey.",
2651
+ "examplePrompts": [
2652
+ "List the drawing layers on this storey",
2653
+ "Show all the PDF underlays on storey st_2",
2654
+ "What CAD layers are on the ground floor?\n\n# Example\n```ts\nconst { layers } = await snaptrude.core.layers.list(\"st_2\")\nfor (const l of layers) console.log(l.name, l.layerType, l.hidden)\n```"
2655
+ ],
2656
+ "argsType": "string",
2657
+ "resultType": "PluginCoreLayersListResult"
2658
+ },
2659
+ {
2660
+ "path": "core.layers.setActive",
2661
+ "namespace": "core.layers",
2662
+ "summary": "Make a drawing layer the active layer of its storey.",
2663
+ "examplePrompts": [
2664
+ "Draw on layer ly_5",
2665
+ "Make this the active layer",
2666
+ "Switch the active layer to the CAD underlay\n\n# Example\n```ts\nawait snaptrude.core.layers.setActive(\"ly_5\")\n```"
2667
+ ],
2668
+ "argsType": "string",
2669
+ "resultType": "PluginCoreLayersSetActiveResult"
2670
+ },
2671
+ {
2672
+ "path": "core.layers.update",
2673
+ "namespace": "core.layers",
2674
+ "summary": "Update a drawing layer's visibility.",
2675
+ "examplePrompts": [
2676
+ "Hide the PDF underlay layer",
2677
+ "Show the CAD layer again",
2678
+ "Hide layer ly_5\n\n# Example\n```ts\nconst layer = await snaptrude.core.layers.update(\"ly_5\", true)\n```"
2679
+ ],
2680
+ "argsType": "string",
2681
+ "resultType": "PluginCoreLayersUpdateResult"
2682
+ },
2683
+ {
2684
+ "path": "core.math.quat.components",
2685
+ "namespace": "core.math.quat",
2686
+ "summary": "Read the primitive `{ x, y, z, w }` components of a quaternion handle.",
2687
+ "examplePrompts": [],
2688
+ "argsType": "QuatHandle",
2689
+ "resultType": "QuatComponents"
2690
+ },
2691
+ {
2692
+ "path": "core.math.quat.conjugate",
2693
+ "namespace": "core.math.quat",
2694
+ "summary": "Compute the conjugate of a quaternion (negated vector part).",
2695
+ "examplePrompts": [],
2696
+ "argsType": "QuatHandle",
2697
+ "resultType": "QuatHandle"
2698
+ },
2699
+ {
2700
+ "path": "core.math.quat.dot",
2701
+ "namespace": "core.math.quat",
2702
+ "summary": "Compute the dot product of two quaternions.",
2703
+ "examplePrompts": [],
2704
+ "argsType": "QuatHandle",
2705
+ "resultType": "number"
2706
+ },
2707
+ {
2708
+ "path": "core.math.quat.equals",
2709
+ "namespace": "core.math.quat",
2710
+ "summary": "Test whether two quaternions have exactly equal components.",
2711
+ "examplePrompts": [],
2712
+ "argsType": "QuatHandle",
2713
+ "resultType": "boolean"
2714
+ },
2715
+ {
2716
+ "path": "core.math.quat.equalsApprox",
2717
+ "namespace": "core.math.quat",
2718
+ "summary": "Test whether two quaternions are equal within a tolerance `epsilon` (default `1e-6`).",
2719
+ "examplePrompts": [],
2720
+ "argsType": "QuatHandle",
2721
+ "resultType": "boolean"
2722
+ },
2723
+ {
2724
+ "path": "core.math.quat.fromAxisAngle",
2725
+ "namespace": "core.math.quat",
2726
+ "summary": "Build a quaternion from a rotation axis and an angle in radians.",
2727
+ "examplePrompts": [],
2728
+ "argsType": "Vec3Handle",
2729
+ "resultType": "QuatHandle"
1920
2730
  },
1921
2731
  {
1922
2732
  "path": "core.math.quat.fromEuler",
@@ -2370,8 +3180,117 @@
2370
3180
  "Make the cursor snap every 6 inches when drawing",
2371
3181
  "Adjust the snapping increment for lengths\n\n# Example\n```ts\n// the threshold only applies while dimension snapping is on\nawait snaptrude.core.project.settings.snaps.setDimension(100)\nawait snaptrude.core.project.settings.snaps.enableDimension()\n```"
2372
3182
  ],
2373
- "argsType": "number",
2374
- "resultType": "boolean"
3183
+ "argsType": "number",
3184
+ "resultType": "boolean"
3185
+ },
3186
+ {
3187
+ "path": "core.proposals.create",
3188
+ "namespace": "core.proposals",
3189
+ "summary": "Create a new design option (proposal) — blank, or configured from a base proposal (the New Proposal modal's two paths).",
3190
+ "examplePrompts": [
3191
+ "Create a design option called Scheme B",
3192
+ "Add a new proposal named Option 2",
3193
+ "Duplicate the current proposal as Scheme C",
3194
+ "Create a design option based on Proposal 1 that shares its site layer\n\n# Example\n```ts\n// blank design option\nconst { id } = await snaptrude.core.proposals.create(\"Scheme B\")\n\n// configured from the active proposal: duplicate every layer\nconst base = await snaptrude.core.proposals.getActive()\nif (base) {\nconst { id: dup } = await snaptrude.core.proposals.create(\"Scheme C\", {\nbaseProposalId: base.id,\n})\n// …or share one layer and leave the rest behind\nconst { id: shared } = await snaptrude.core.proposals.create(\"Scheme D\", {\nbaseProposalId: base.id,\nlayers: [{ bucketId: base.defaultBucketId, action: \"share\" }],\n})\n}\n```"
3195
+ ],
3196
+ "argsType": "string",
3197
+ "resultType": "PluginCoreProposalsCreateResult"
3198
+ },
3199
+ {
3200
+ "path": "core.proposals.delete",
3201
+ "namespace": "core.proposals",
3202
+ "summary": "Delete a proposal.",
3203
+ "examplePrompts": [
3204
+ "Delete proposal prop_2 and everything in it",
3205
+ "Remove this design option and destroy its geometry",
3206
+ "Merge prop_2's layers into prop_1 and delete prop_2\n\n# Example\n```ts\n// destroy the proposal and its exclusive geometry\nawait snaptrude.core.proposals.delete(\"prop_2\", { deleteObjects: true })\n// …or keep the geometry by transferring its buckets to prop_1 first\nawait snaptrude.core.proposals.delete(\"prop_2\", { targetProposalId: \"prop_1\" })\n```"
3207
+ ],
3208
+ "argsType": "string",
3209
+ "resultType": "PluginCoreProposalsDeleteResult"
3210
+ },
3211
+ {
3212
+ "path": "core.proposals.get",
3213
+ "namespace": "core.proposals",
3214
+ "summary": "Get a single proposal by id.",
3215
+ "examplePrompts": [
3216
+ "Get the proposal with id prop_1",
3217
+ "Look up a single design option by its id",
3218
+ "Which buckets belong to proposal prop_2?\n\n# Example\n```ts\nconst proposal = await snaptrude.core.proposals.get(\"prop_1\")\nif (proposal) console.log(proposal.name, proposal.bucketIds)\n```"
3219
+ ],
3220
+ "argsType": "string",
3221
+ "resultType": "PluginCoreProposalsGetResult"
3222
+ },
3223
+ {
3224
+ "path": "core.proposals.getActive",
3225
+ "namespace": "core.proposals",
3226
+ "summary": "Get the active proposal.",
3227
+ "examplePrompts": [
3228
+ "Which design option is active?",
3229
+ "Get the current proposal",
3230
+ "What proposal am I working in?\n\n# Example\n```ts\nconst active = await snaptrude.core.proposals.getActive()\nif (active) console.log(active.id, active.name)\n```"
3231
+ ],
3232
+ "argsType": null,
3233
+ "resultType": "PluginCoreProposalsGetActiveResult"
3234
+ },
3235
+ {
3236
+ "path": "core.proposals.isActive",
3237
+ "namespace": "core.proposals",
3238
+ "summary": "Test whether a proposal is the active one.",
3239
+ "examplePrompts": [
3240
+ "Is proposal prop_2 the active one?",
3241
+ "Check whether this design option is currently shown",
3242
+ "Am I working in proposal prop_1?\n\n# Example\n```ts\nif (await snaptrude.core.proposals.isActive(\"prop_1\")) {\nconsole.log(\"prop_1 is active\")\n}\n```"
3243
+ ],
3244
+ "argsType": "string",
3245
+ "resultType": "boolean"
3246
+ },
3247
+ {
3248
+ "path": "core.proposals.list",
3249
+ "namespace": "core.proposals",
3250
+ "summary": "List the design options (proposals) in the active project.",
3251
+ "examplePrompts": [
3252
+ "List all the design options in this project",
3253
+ "How many proposals does this project have?",
3254
+ "Show every design variant with its name\n\n# Example\n```ts\nconst { proposals } = await snaptrude.core.proposals.list()\nfor (const p of proposals) console.log(p.id, p.name, p.isActive)\n```"
3255
+ ],
3256
+ "argsType": null,
3257
+ "resultType": "PluginCoreProposalsListResult"
3258
+ },
3259
+ {
3260
+ "path": "core.proposals.listForComponent",
3261
+ "namespace": "core.proposals",
3262
+ "summary": "List the proposals a component belongs to.",
3263
+ "examplePrompts": [
3264
+ "Which design options is this component part of?",
3265
+ "List the proposals that contain this wall",
3266
+ "Is this element shared across multiple design variants?\n\n# Example\n```ts\nconst { proposals } = await snaptrude.core.proposals.listForComponent(wall)\nconsole.log(`shared across ${proposals.length} proposals`)\n```"
3267
+ ],
3268
+ "argsType": "ComponentHandle",
3269
+ "resultType": "PluginCoreProposalsListForComponentResult"
3270
+ },
3271
+ {
3272
+ "path": "core.proposals.rename",
3273
+ "namespace": "core.proposals",
3274
+ "summary": "Rename a proposal.",
3275
+ "examplePrompts": [
3276
+ "Rename proposal prop_1 to Final Scheme",
3277
+ "Change the name of this design option",
3278
+ "Call proposal prop_2 \"Option A\"\n\n# Example\n```ts\nconst proposal = await snaptrude.core.proposals.rename(\"prop_1\", \"Final Scheme\")\n```"
3279
+ ],
3280
+ "argsType": "string",
3281
+ "resultType": "PluginCoreProposalsRenameResult"
3282
+ },
3283
+ {
3284
+ "path": "core.proposals.setActive",
3285
+ "namespace": "core.proposals",
3286
+ "summary": "Switch the active proposal.",
3287
+ "examplePrompts": [
3288
+ "Switch to proposal prop_2",
3289
+ "Make Scheme B the active design option",
3290
+ "Show me the other proposal\n\n# Example\n```ts\nawait snaptrude.core.proposals.setActive(\"prop_2\")\n```"
3291
+ ],
3292
+ "argsType": "string",
3293
+ "resultType": "PluginCoreProposalsSetActiveResult"
2375
3294
  },
2376
3295
  {
2377
3296
  "path": "core.tags.assign",
@@ -2606,6 +3525,19 @@
2606
3525
  "argsType": "PUnitType",
2607
3526
  "resultType": "boolean"
2608
3527
  },
3528
+ {
3529
+ "path": "core.user.getLocale",
3530
+ "namespace": "core.user",
3531
+ "summary": "Get the viewer's locale: IANA timezone and BCP-47 language tag, resolved from the browser (`Intl.DateTimeFormat().resolvedOptions().timeZone` and `navigator.language`). Locale only — no precise location.",
3532
+ "examplePrompts": [
3533
+ "What timezone is the user in?",
3534
+ "Get the viewer's language for localized labels",
3535
+ "Format the report date in the user's local timezone",
3536
+ "Which locale should I use for this plugin's UI?\n\n# Example\n```ts\nconst { timezone, language } = await snaptrude.core.user.getLocale()\n```"
3537
+ ],
3538
+ "argsType": null,
3539
+ "resultType": "PluginUserLocale"
3540
+ },
2609
3541
  {
2610
3542
  "path": "core.zoom.extents",
2611
3543
  "namespace": "core.zoom",
@@ -2677,7 +3609,7 @@
2677
3609
  {
2678
3610
  "path": "design.create.beam",
2679
3611
  "namespace": "design.create",
2680
- "summary": "Create a **beam** by extruding a cross-section contour along `direction` by `length`.",
3612
+ "summary": "Create a **beam** by extruding a cross-section contour along `direction` by `length`. Matches the Snaptrude beam tool's semantics: the beam body hangs BELOW the plane the section is authored on.",
2681
3613
  "examplePrompts": [
2682
3614
  "Add a beam spanning 6 metres between the columns",
2683
3615
  "Create a horizontal beam along the X axis",
@@ -2703,7 +3635,7 @@
2703
3635
  {
2704
3636
  "path": "design.create.column",
2705
3637
  "namespace": "design.create",
2706
- "summary": "Create a **column** by extruding a cross-section contour upward by `height` from a base `position`.",
3638
+ "summary": "Create a **column** by extruding a cross-section contour upward by `height` from a base `position`. The column is built to EXACTLY `height` — unlike the interactive draw tool, no slab-thickness deduction is applied.",
2707
3639
  "examplePrompts": [
2708
3640
  "Add a 3m tall column at this point",
2709
3641
  "Place a column at the grid intersection",
@@ -2727,6 +3659,21 @@
2727
3659
  "argsType": "ComponentHandle[]",
2728
3660
  "resultType": "ComponentHandle[]"
2729
3661
  },
3662
+ {
3663
+ "path": "design.create.door",
3664
+ "namespace": "design.create",
3665
+ "summary": "Place a **door** from the catalog into a host wall.",
3666
+ "examplePrompts": [
3667
+ "Add a door to this wall here",
3668
+ "Place a sliding door on the selected wall",
3669
+ "Put a door from the catalog at this point on the wall",
3670
+ "Insert the entrance door into this wall",
3671
+ "Add a door to the wall and call it Entry-01",
3672
+ "Add a door that opens into the living room\n\n# Example\n```ts\nconst [wall] = await snaptrude.design.query.listWalls({ isSelected: true })\nconst [entry] = await snaptrude.design.doors.listCatalog()\nconst door = await snaptrude.design.create.door(\nentry.id,\nwall,\nawait snaptrude.core.math.vec3.new(3, 0, 5),\n{ label: \"Entry-01\" },\n)\n// …facing a specific side of the wall (pass a point inside that room):\nconst intoKitchen = await snaptrude.design.create.door(\nentry.id,\nwall,\nawait snaptrude.core.math.vec3.new(3, 0, 5),\nundefined,\nawait snaptrude.core.math.vec3.new(3, 0, 9),\n)\n```"
3673
+ ],
3674
+ "argsType": "string",
3675
+ "resultType": "ComponentHandle"
3676
+ },
2730
3677
  {
2731
3678
  "path": "design.create.floor",
2732
3679
  "namespace": "design.create",
@@ -2749,7 +3696,8 @@
2749
3696
  "Add a sofa from the furniture catalog to the living room",
2750
3697
  "Drop a desk into the scene at 3, 0, 5",
2751
3698
  "Insert the uploaded bed model in the bedroom",
2752
- "Put a table from my project library here and name it Table-01\n\n# Example\n```ts\nconst chair = await snaptrude.design.create.furniture(\n\"6620f1a…\", // from design.furniture.listCatalog()\nawait snaptrude.core.math.vec3.new(3, 0, 5),\n{ label: \"Chair-01\" },\n)\n```"
3699
+ "Put a table from my project library here and name it Table-01",
3700
+ "Place a chair here rotated 90 degrees\n\n# Example\n```ts\nconst chair = await snaptrude.design.create.furniture(\n\"6620f1a…\", // from design.furniture.listCatalog()\nawait snaptrude.core.math.vec3.new(3, 0, 5),\n{ label: \"Chair-01\" },\n)\n// …placed already turned 90° about the vertical axis:\nconst turned = await snaptrude.design.create.furniture(\n\"6620f1a…\",\nawait snaptrude.core.math.vec3.new(3, 0, 5),\nundefined,\n90,\n)\n```"
2753
3701
  ],
2754
3702
  "argsType": "string",
2755
3703
  "resultType": "ComponentHandle"
@@ -2808,6 +3756,20 @@
2808
3756
  "argsType": "ContourHandle",
2809
3757
  "resultType": "ComponentHandle"
2810
3758
  },
3759
+ {
3760
+ "path": "design.create.smartLayout",
3761
+ "namespace": "design.create",
3762
+ "summary": "Place a **smart layout** — clone an in-scene template cluster (walls, furniture, doors, windows, floors) into one or more target ROOM/DEPARTMENT spaces, adapting orientation and fit to each target.",
3763
+ "examplePrompts": [
3764
+ "Copy this room's layout into the selected rooms",
3765
+ "Apply this furniture arrangement to the other offices",
3766
+ "Replicate this template into these two spaces",
3767
+ "Place this desk cluster into every meeting room",
3768
+ "Use this room as a template for the rooms I selected but keep them visible\n\n# Example\n```ts\nconst [templateRoom, ...targets] = await snaptrude.design.query.listSpaces({ isSelected: true })\nconst result = await snaptrude.design.create.smartLayout({\ntemplateComponents: [templateRoom],\ntargets,\n})\nconsole.log(\"placed walls:\", result.created.walls.length, \"skipped:\", result.skippedWalls)\n\n// …or clone a saved group by its id (from core.groups.list)\nconst { groups } = await snaptrude.core.groups.list()\nawait snaptrude.design.create.smartLayout({ templateGroup: groups[0].id, targets })\n```"
3769
+ ],
3770
+ "argsType": "PluginSmartLayoutArgs",
3771
+ "resultType": "PluginSmartLayoutResult"
3772
+ },
2811
3773
  {
2812
3774
  "path": "design.create.space",
2813
3775
  "namespace": "design.create",
@@ -2817,7 +3779,8 @@
2817
3779
  "Add a new space on the current storey using this footprint",
2818
3780
  "Make a bedroom here and assign it to the Residential department",
2819
3781
  "Extrude this closed outline into a 10 foot high room",
2820
- "Can you create a Kitchen space from the sketch I just drew?\n\n# Example\n```ts\nconst v = snaptrude.core.math.vec3\nconst outer = await snaptrude.core.geom.create.profileFromLinePoints([\nawait v.new(0, 0, 0),\nawait v.new(10, 0, 0),\nawait v.new(10, 0, 8),\nawait v.new(0, 0, 8),\n])\nconst contour = await snaptrude.core.geom.create.contourFromProfile(outer)\nconst space = await snaptrude.design.create.space(contour, 3, \"Living\")\n```"
3782
+ "Can you create a Kitchen space from the sketch I just drew?",
3783
+ "Create a bedroom on the second floor from this outline\n\n# Example\n```ts\nconst v = snaptrude.core.math.vec3\nconst outer = await snaptrude.core.geom.create.profileFromLinePoints([\nawait v.new(0, 0, 0),\nawait v.new(10, 0, 0),\nawait v.new(10, 0, 8),\nawait v.new(0, 0, 8),\n])\nconst contour = await snaptrude.core.geom.create.contourFromProfile(outer)\nconst space = await snaptrude.design.create.space(contour, 3, \"Living\")\n// …place one directly on the second floor (no setActive dance):\nconst upstairs = await snaptrude.design.create.space(\ncontour, 3, \"Bedroom\", undefined, undefined, undefined, undefined, 2,\n)\n```"
2821
3784
  ],
2822
3785
  "argsType": "ContourHandle",
2823
3786
  "resultType": "ComponentHandle"
@@ -2825,12 +3788,13 @@
2825
3788
  {
2826
3789
  "path": "design.create.spaces",
2827
3790
  "namespace": "design.create",
2828
- "summary": "Create **many spaces** in one undoable operation (bulk plural of {@linkcode space}). Migrated from the removed `entity.space.bulkCreate`. Each item extrudes a contour footprint up `height`. Validate-all-or-throw; one command. For a rectangular (box) space, build the footprint with `core.geom.create.profileRect` → `contourFromProfile`, then pass it as an item.",
3791
+ "summary": "Create **many spaces** in one undoable operation (bulk plural of {@linkcode space}). Migrated from the removed `entity.space.bulkCreate`. Each item extrudes a contour footprint up `height`. Validate-all-or-throw; one command. For a rectangular (box) space, build the footprint with `core.geom.create.profileRect` → `contourFromProfile`, then pass it as an item. Each item may carry its own `storey` (see {@linkcode PluginCreateSpaceItem}) so a single call can populate several floors at once.",
2829
3792
  "examplePrompts": [
2830
3793
  "Create several rooms at once from these footprints",
2831
3794
  "Generate all the bedrooms in one operation",
2832
3795
  "Bulk create the spaces for this floor plan",
2833
- "Add three rooms with different heights in a single undo step\n\n# Example\n```ts\nconst rect = await snaptrude.core.geom.create.profileRect(4, 3)\nconst contour = await snaptrude.core.geom.create.contourFromProfile(rect)\nconst [a, b] = await snaptrude.design.create.spaces([\n{ contour, height: 3, label: \"R1\" },\n{ contour, height: 4, label: \"R2\", position: await vec3.new(10, 0, 0) },\n])\n```"
3796
+ "Add three rooms with different heights in a single undo step",
3797
+ "Create one room on the ground floor and one on the first floor\n\n# Example\n```ts\nconst rect = await snaptrude.core.geom.create.profileRect(4, 3)\nconst contour = await snaptrude.core.geom.create.contourFromProfile(rect)\nconst [a, b] = await snaptrude.design.create.spaces([\n{ contour, height: 3, label: \"R1\" },\n{ contour, height: 4, label: \"R2\", position: await vec3.new(10, 0, 0) },\n])\n```"
2834
3798
  ],
2835
3799
  "argsType": "PluginCreateSpaceItem[]",
2836
3800
  "resultType": "ComponentHandle[]"
@@ -2858,11 +3822,28 @@
2858
3822
  "Create 3m high, 200mm thick walls from these points",
2859
3823
  "Build a wall run around the room outline",
2860
3824
  "Turn this polyline sketch into walls",
2861
- "Add walls with mitred corners along the path\n\n# Example\n```ts\nconst v = snaptrude.core.math.vec3\nconst centerlines = await snaptrude.core.geom.create.profileFromLinePoints([\nawait v.new(0, 0, 0),\nawait v.new(8, 0, 0),\nawait v.new(8, 0, 6),\n])\nconst walls = await snaptrude.design.create.walls(centerlines, 3, 0.2)\n```"
3825
+ "Add walls with mitred corners along the path",
3826
+ "Draw brick walls with plaster along this outline",
3827
+ "Build the perimeter in exposed concrete walls\n\n# Example\n```ts\nconst v = snaptrude.core.math.vec3\nconst centerlines = await snaptrude.core.geom.create.profileFromLinePoints([\nawait v.new(0, 0, 0),\nawait v.new(8, 0, 0),\nawait v.new(8, 0, 6),\n])\nconst walls = await snaptrude.design.create.walls(centerlines, 3, 0.2)\n// …built as a specific wall type (layers/material/thickness from the type):\nconst [brick] = await snaptrude.design.types.list(\"wall\")\nconst brickWalls = await snaptrude.design.create.walls(\ncenterlines, 3, undefined, brick.label,\n)\n```"
2862
3828
  ],
2863
3829
  "argsType": "ProfileHandle",
2864
3830
  "resultType": "ComponentHandle[]"
2865
3831
  },
3832
+ {
3833
+ "path": "design.create.window",
3834
+ "namespace": "design.create",
3835
+ "summary": "Place a **window** from the catalog into a host wall.",
3836
+ "examplePrompts": [
3837
+ "Add a window to this wall here",
3838
+ "Place a casement window on the selected wall",
3839
+ "Put a window from the catalog at this point on the wall",
3840
+ "Insert a window into the living room wall",
3841
+ "Add a window to the wall and name it Win-01",
3842
+ "Add a casement window opening toward the garden side\n\n# Example\n```ts\nconst [wall] = await snaptrude.design.query.listWalls({ isSelected: true })\nconst [entry] = await snaptrude.design.windows.listCatalog()\nconst window = await snaptrude.design.create.window(\nentry.id,\nwall,\nawait snaptrude.core.math.vec3.new(3, 0, 5),\n{ label: \"Win-01\" },\n)\n```"
3843
+ ],
3844
+ "argsType": "string",
3845
+ "resultType": "ComponentHandle"
3846
+ },
2866
3847
  {
2867
3848
  "path": "design.delete.entities",
2868
3849
  "namespace": "design.delete",
@@ -2877,6 +3858,45 @@
2877
3858
  "argsType": "ComponentHandle[]",
2878
3859
  "resultType": "PluginDesignChangeResult"
2879
3860
  },
3861
+ {
3862
+ "path": "design.doors.exists",
3863
+ "namespace": "design.doors",
3864
+ "summary": "Test whether a door catalog item exists for the given library id.",
3865
+ "examplePrompts": [
3866
+ "Is this door still in the library?",
3867
+ "Check whether a door catalog item with this id exists",
3868
+ "Does my team library have this door?",
3869
+ "Verify the door is available before placing it\n\n# Example\n```ts\nconst [entry] = await snaptrude.design.doors.listCatalog()\nconst stillAvailable = await snaptrude.design.doors.exists(entry.id)\nconsole.log(stillAvailable ? \"safe to place\" : \"removed from library\")\n```"
3870
+ ],
3871
+ "argsType": "string",
3872
+ "resultType": "boolean"
3873
+ },
3874
+ {
3875
+ "path": "design.doors.getCatalogItem",
3876
+ "namespace": "design.doors",
3877
+ "summary": "Get a single door catalog item by its library id.",
3878
+ "examplePrompts": [
3879
+ "Get the details of this door from the library",
3880
+ "Look up the catalog entry for this door id",
3881
+ "What is the cost of this door item?",
3882
+ "Show me the family name of this door in the catalog\n\n# Example\n```ts\nconst [entry] = await snaptrude.design.doors.listCatalog()\nconst item = await snaptrude.design.doors.getCatalogItem(entry.id)\nif (item) console.log(item.name, item.source, item.dbType)\n```"
3883
+ ],
3884
+ "argsType": "string",
3885
+ "resultType": "PluginObjectCatalogItem | null"
3886
+ },
3887
+ {
3888
+ "path": "design.doors.getDimensions",
3889
+ "namespace": "design.doors",
3890
+ "summary": "Get a door's full dimensions in one call — width along the wall, vertical height, and thickness through the wall — measured in the door's local oriented space. Parity with {@linkcode PluginDesignWindowsApi.getDimensions}.",
3891
+ "examplePrompts": [
3892
+ "What are the dimensions of this door?",
3893
+ "How big is the selected door?",
3894
+ "Give me the width, height and depth of this door",
3895
+ "Measure the entrance door including its thickness through the wall\n\n# Example\n```ts\nconst [door] = await snaptrude.design.query.listDoors({ isSelected: true })\nconst dims = await snaptrude.design.doors.getDimensions(door)\nif (dims) console.log(dims.width, dims.height, dims.thickness)\n```"
3896
+ ],
3897
+ "argsType": "ComponentHandle",
3898
+ "resultType": "PluginDoorDimensions | null"
3899
+ },
2880
3900
  {
2881
3901
  "path": "design.doors.getFamily",
2882
3902
  "namespace": "design.doors",
@@ -2955,6 +3975,32 @@
2955
3975
  "argsType": "ComponentHandle",
2956
3976
  "resultType": "number | null"
2957
3977
  },
3978
+ {
3979
+ "path": "design.doors.listCatalog",
3980
+ "namespace": "design.doors",
3981
+ "summary": "List the placeable door catalog (team + general libraries), optionally restricted to one group by its `dbType` token.",
3982
+ "examplePrompts": [
3983
+ "What doors can I place in this project?",
3984
+ "List every door in the library",
3985
+ "Show me the sliding doors I can add",
3986
+ "Browse the door catalog\n\n# Example\n```ts\nconst [group] = await snaptrude.design.doors.listCatalogGroups()\nconst items = await snaptrude.design.doors.listCatalog(group?.dbType)\nfor (const item of items) console.log(item.id, item.name, item.thumbnailUrl)\n```"
3987
+ ],
3988
+ "argsType": "string",
3989
+ "resultType": "PluginObjectCatalogItem[]"
3990
+ },
3991
+ {
3992
+ "path": "design.doors.listCatalogGroups",
3993
+ "namespace": "design.doors",
3994
+ "summary": "List the door catalog **groups** — the placement families (Swing, Sliding, Folding, Pivot, …), built-in groups merged with any team-custom types.",
3995
+ "examplePrompts": [
3996
+ "What kinds of doors can I place?",
3997
+ "List the door groups in the catalog",
3998
+ "Show me the door families available in this project",
3999
+ "Which door types does this project support?\n\n# Example\n```ts\nconst groups = await snaptrude.design.doors.listCatalogGroups()\nfor (const g of groups) console.log(g.dbType, g.label, g.source)\n```"
4000
+ ],
4001
+ "argsType": null,
4002
+ "resultType": "PluginObjectCatalogGroup[]"
4003
+ },
2958
4004
  {
2959
4005
  "path": "design.doors.mirror",
2960
4006
  "namespace": "design.doors",
@@ -3062,20 +4108,71 @@
3062
4108
  "argsType": "string",
3063
4109
  "resultType": "PluginFurnitureCatalogItem | null"
3064
4110
  },
4111
+ {
4112
+ "path": "design.furniture.getDimensions",
4113
+ "namespace": "design.furniture",
4114
+ "summary": "Get the dimensions of a PLACED furniture item — `length` (along the object), `width` (across it) and `height` (vertical), in engine units. Mirrors the Length/Width/Height fields of the furniture properties panel.",
4115
+ "examplePrompts": [
4116
+ "How big is this sofa?",
4117
+ "What are the dimensions of the selected furniture?",
4118
+ "Measure the length, width and height of this table",
4119
+ "Get the size of the chair I just placed\n\n# Example\n```ts\nconst [item] = await snaptrude.design.query.listFurniture({ isSelected: true })\nconst dims = await snaptrude.design.furniture.getDimensions(item)\nif (dims) console.log(dims.length, dims.width, dims.height)\n```"
4120
+ ],
4121
+ "argsType": "ComponentHandle",
4122
+ "resultType": "PluginFurnitureDimensions | null"
4123
+ },
3065
4124
  {
3066
4125
  "path": "design.furniture.listCatalog",
3067
4126
  "namespace": "design.furniture",
3068
- "summary": "List the placeable furniture catalog (team + general libraries).",
4127
+ "summary": "List the placeable furniture catalog (team + general libraries), optionally filtered by library `source` and/or `category`.",
3069
4128
  "examplePrompts": [
3070
4129
  "What furniture can I place in this project?",
3071
4130
  "Show me all the furniture available in the library",
3072
4131
  "List the chairs and tables I can add to the model",
3073
4132
  "Which furniture items are in my team's library?",
3074
- "Browse the furniture catalog\n\n# Example\n```ts\nconst teamItems = await snaptrude.design.furniture.listCatalog(\"team\")\nfor (const item of teamItems) console.log(item.id, item.name, item.cost)\n```"
4133
+ "Show me the bedroom furniture I can place\n\n# Example\n```ts\nconst bedroom = await snaptrude.design.furniture.listCatalog(\"team\", \"bedroom\")\nfor (const item of bedroom) console.log(item.id, item.name, item.thumbnailUrl)\n```"
3075
4134
  ],
3076
4135
  "argsType": "\"team\" | \"general\"",
3077
4136
  "resultType": "PluginFurnitureCatalogItem[]"
3078
4137
  },
4138
+ {
4139
+ "path": "design.furniture.listCategories",
4140
+ "namespace": "design.furniture",
4141
+ "summary": "List the categories (Living, Bedroom, Kitchen, …) that organize the furniture catalog — the picker taxonomy, merged from built-in categories, team types, and backend user types. Pass a value to {@linkcode PluginDesignFurnitureApi.listCatalog}'s `category` filter.",
4142
+ "examplePrompts": [
4143
+ "What furniture categories are available?",
4144
+ "List the furniture categories",
4145
+ "Show me the furniture groups like living and bedroom",
4146
+ "Which furniture categories can I filter by?\n\n# Example\n```ts\nconst categories = await snaptrude.design.furniture.listCategories()\nconst [first] = categories\nconst items = await snaptrude.design.furniture.listCatalog(undefined, first)\nconsole.log(first, \"→\", items.length, \"items\")\n```"
4147
+ ],
4148
+ "argsType": null,
4149
+ "resultType": "string[]"
4150
+ },
4151
+ {
4152
+ "path": "design.furniture.setDimensions",
4153
+ "namespace": "design.furniture",
4154
+ "summary": "Resize a PLACED furniture item along one or more axes — `length`, `width` and/or `height` (engine units). Omitted axes are left unchanged. Each supplied axis is an undoable command, mirroring editing the furniture properties panel.",
4155
+ "examplePrompts": [
4156
+ "Make this table 1.8m long",
4157
+ "Resize the selected sofa to 2000 wide",
4158
+ "Set this furniture to 800mm tall",
4159
+ "Change the desk to 1500 long and 700 deep\n\n# Example\n```ts\nconst [item] = await snaptrude.design.query.listFurniture({ isSelected: true })\nconst { affected } = await snaptrude.design.furniture.setDimensions(item, {\nlength: 1800,\nheight: 750\n})\n```"
4160
+ ],
4161
+ "argsType": "ComponentHandle",
4162
+ "resultType": "PluginDesignChangeResult"
4163
+ },
4164
+ {
4165
+ "path": "design.isAreaLocked",
4166
+ "namespace": "design",
4167
+ "summary": "Test whether a space's footprint area is locked. A read — never throws; returns `false` for non-space handles and when the `area_lock` feature is off.",
4168
+ "examplePrompts": [
4169
+ "Is the area of this room locked?",
4170
+ "Check whether this department's footprint is pinned",
4171
+ "Tell me if the selected space has its area locked\n\n# Example\n```ts\nconst [room] = await snaptrude.design.selection.get()\nconst locked = await snaptrude.design.isAreaLocked(room)\nconsole.log(locked ? \"area is locked\" : \"area is free\")\n```"
4172
+ ],
4173
+ "argsType": "ComponentHandle",
4174
+ "resultType": "boolean"
4175
+ },
3079
4176
  {
3080
4177
  "path": "design.isLocked",
3081
4178
  "namespace": "design",
@@ -3089,6 +4186,18 @@
3089
4186
  "argsType": "ComponentHandle",
3090
4187
  "resultType": "boolean"
3091
4188
  },
4189
+ {
4190
+ "path": "design.listAreaLocked",
4191
+ "namespace": "design",
4192
+ "summary": "List the spaces whose footprint area is locked. A read — never throws; returns `[]` when the `area_lock` feature is off.",
4193
+ "examplePrompts": [
4194
+ "Which spaces have their area locked?",
4195
+ "List every room with a locked footprint",
4196
+ "Show me all the area-locked departments\n\n# Example\n```ts\nconst locked = await snaptrude.design.listAreaLocked()\nconsole.log(locked.length, \"area-locked spaces\")\n```"
4197
+ ],
4198
+ "argsType": null,
4199
+ "resultType": "ComponentHandle[]"
4200
+ },
3092
4201
  {
3093
4202
  "path": "design.listLocked",
3094
4203
  "namespace": "design",
@@ -3115,6 +4224,19 @@
3115
4224
  "argsType": "ComponentHandle[]",
3116
4225
  "resultType": "PluginDesignChangeResult"
3117
4226
  },
4227
+ {
4228
+ "path": "design.lockArea",
4229
+ "namespace": "design",
4230
+ "summary": "Lock the **footprint area** of one or more Room / Department mass spaces — geometry edits that would change the bottom-face area are then refused or auto-resized to preserve it. Distinct from {@linkcode PluginDesignApi.lock} (which freezes the whole object): this locks only the area. Cascades to the space's instances and its source mass. Undoable.",
4231
+ "examplePrompts": [
4232
+ "Lock the floor area of the selected rooms",
4233
+ "Freeze the footprint area of this department so its size can't drift",
4234
+ "Area-lock every room on this storey",
4235
+ "Pin the area of this space while I edit its walls\n\n# Example\n```ts\nconst rooms = await snaptrude.design.selection.get()\nconst { affected } = await snaptrude.design.lockArea(rooms)\nconsole.log(\"area-locked\", affected.length, \"spaces\")\n```"
4236
+ ],
4237
+ "argsType": "ComponentHandle[]",
4238
+ "resultType": "PluginDesignChangeResult"
4239
+ },
3118
4240
  {
3119
4241
  "path": "design.materials.apply",
3120
4242
  "namespace": "design.materials",
@@ -3129,6 +4251,19 @@
3129
4251
  "argsType": "ComponentHandle[]",
3130
4252
  "resultType": "PluginMaterialResult"
3131
4253
  },
4254
+ {
4255
+ "path": "design.materials.applyToFaces",
4256
+ "namespace": "design.materials",
4257
+ "summary": "Paint specific **BREP faces** of a component with a material — an existing project material by handle, or a new one described inline as a {@linkcode PluginMaterialSpec}. Faces are addressed by **durable BREP face index** (their 0-based position in the component's BREP face list). Undoable when `save` is true (the default).",
4258
+ "examplePrompts": [
4259
+ "Paint the top face of this slab red",
4260
+ "Apply the brick material to faces 0 and 2 of this wall",
4261
+ "Put a wood finish on just the front face of this column",
4262
+ "Colour face 4 of the selected mass with #ff8800\n\n# Example\n```ts\nconst [wall] = await snaptrude.design.query.listWalls({ storeys: [1] })\n// faces are addressed by durable 0-based BREP face index\nconst { count } = await snaptrude.design.materials.applyToFaces(wall, [0, 1], { name: \"Accent\", color: \"#b04a3a\" })\nconsole.log(\"painted\", count, \"faces\")\n```"
4263
+ ],
4264
+ "argsType": "ComponentHandle",
4265
+ "resultType": "PluginMaterialResult"
4266
+ },
3132
4267
  {
3133
4268
  "path": "design.materials.create",
3134
4269
  "namespace": "design.materials",
@@ -3142,6 +4277,32 @@
3142
4277
  "argsType": "PluginMaterialSpec",
3143
4278
  "resultType": "MaterialHandle"
3144
4279
  },
4280
+ {
4281
+ "path": "design.materials.get",
4282
+ "namespace": "design.materials",
4283
+ "summary": "Read the material applied to a component **as a whole** — the eyedropper. For a uniformly-painted component this is that single material; for a per-face-painted component it is the material on the component's base/first face. Use {@linkcode PluginDesignMaterialsApi.getByFace} / {@linkcode PluginDesignMaterialsApi.listByFace} for the per-face breakdown.",
4284
+ "examplePrompts": [
4285
+ "What material is on this wall?",
4286
+ "Eyedrop the finish of the selected object",
4287
+ "Which material does this slab use?",
4288
+ "Read the material on this column so I can paint others with it",
4289
+ "Is this component painted, and with what?\n\n# Example\n```ts\nconst [component] = await snaptrude.design.selection.get()\nconst sampled = await snaptrude.design.materials.get(component)\nif (sampled) {\nconsole.log(sampled.name, sampled.source) // e.g. \"Brick Red\" \"applied\"\nconst info = await snaptrude.design.materials.getInfo(sampled.material)\nconsole.log(info?.colorHex)\n}\n```"
4290
+ ],
4291
+ "argsType": "ComponentHandle",
4292
+ "resultType": "PluginComponentMaterial | null"
4293
+ },
4294
+ {
4295
+ "path": "design.materials.getByFace",
4296
+ "namespace": "design.materials",
4297
+ "summary": "Read the material applied to a single BREP face.",
4298
+ "examplePrompts": [
4299
+ "What material is on the top face of this slab?",
4300
+ "Get the finish applied to face 2 of this wall",
4301
+ "Which material is painted on the front face of this column?\n\n# Example\n```ts\nconst [wall] = await snaptrude.design.query.listWalls()\nconst material = await snaptrude.design.materials.getByFace(wall, 0)\nif (material) console.log(await snaptrude.design.materials.getInfo(material))\n```"
4302
+ ],
4303
+ "argsType": "ComponentHandle",
4304
+ "resultType": "MaterialHandle | null"
4305
+ },
3145
4306
  {
3146
4307
  "path": "design.materials.getDefault",
3147
4308
  "namespace": "design.materials",
@@ -3210,17 +4371,41 @@
3210
4371
  {
3211
4372
  "path": "design.materials.list",
3212
4373
  "namespace": "design.materials",
3213
- "summary": "List the project materials.",
4374
+ "summary": "List the materials loaded in the project — every named material in the live scene (applied finishes, plugin-created materials, and type defaults in use). For the browsable preset/library catalog (finishes not yet in the project), use {@linkcode PluginDesignMaterialsApi.listPresets}.",
3214
4375
  "examplePrompts": [
3215
4376
  "List all the materials in this project",
3216
4377
  "What materials do I have available to apply?",
3217
- "Show me the preset materials library",
3218
4378
  "Which finishes exist in this model?",
3219
- "Get every material in the project palette\n\n# Example\n```ts\nconst presets = await snaptrude.design.materials.list(\"preset\")\nconsole.log(presets.length, \"preset materials\")\n```"
4379
+ "Get every material in the project palette\n\n# Example\n```ts\nconst materials = await snaptrude.design.materials.list()\nconsole.log(materials.length, \"materials in the project\")\n```"
3220
4380
  ],
3221
- "argsType": "\"project\" | \"preset\"",
4381
+ "argsType": null,
3222
4382
  "resultType": "MaterialHandle[]"
3223
4383
  },
4384
+ {
4385
+ "path": "design.materials.listByFace",
4386
+ "namespace": "design.materials",
4387
+ "summary": "List the per-face materials of a component — one entry per BREP face, in face index order. A face carrying no explicit per-face material reports `null`.",
4388
+ "examplePrompts": [
4389
+ "List the material on every face of this wall",
4390
+ "Show me which faces of this slab are painted and with what",
4391
+ "Break down the per-face finishes of the selected mass\n\n# Example\n```ts\nconst [wall] = await snaptrude.design.query.listWalls()\nconst faces = await snaptrude.design.materials.listByFace(wall)\nfor (const f of faces) console.log(f.faceIndex, f.material ?? \"(default)\")\n```"
4392
+ ],
4393
+ "argsType": "ComponentHandle",
4394
+ "resultType": "PluginFaceMaterial[]"
4395
+ },
4396
+ {
4397
+ "path": "design.materials.listPresets",
4398
+ "namespace": "design.materials",
4399
+ "summary": "List the preset material library — the catalog the app's material browser shows (the built-in finishes plus the workspace's uploaded materials), fetched from the material library service. Library entries are **not** scene materials and carry no {@linkcode MaterialHandle}; each is a named texture record. To use one, feed it to {@linkcode PluginDesignMaterialsApi.create} / {@linkcode PluginDesignMaterialsApi.apply} as a {@linkcode PluginMaterialSpec}: `{ name, textureUrl, materialType: category }`.",
4400
+ "examplePrompts": [
4401
+ "Show me the preset materials library",
4402
+ "What wood finishes are available in the material library?",
4403
+ "Browse the material catalog and apply a brick texture",
4404
+ "Which preset materials can I choose from?\n\n# Example\n```ts\nconst presets = await snaptrude.design.materials.listPresets()\nconst brick = presets.find((p) => p.category.toLowerCase().includes(\"brick\"))\nif (brick) {\nconst walls = await snaptrude.design.query.listWalls()\nawait snaptrude.design.materials.apply(walls, {\nname: brick.name,\ntextureUrl: brick.textureUrl,\nmaterialType: brick.category,\n})\n}\n```"
4405
+ ],
4406
+ "argsType": null,
4407
+ "resultType": "PluginPresetMaterial[]"
4408
+ },
3224
4409
  {
3225
4410
  "path": "design.materials.reset",
3226
4411
  "namespace": "design.materials",
@@ -3234,6 +4419,18 @@
3234
4419
  "argsType": "ComponentHandle[]",
3235
4420
  "resultType": "PluginMaterialResult"
3236
4421
  },
4422
+ {
4423
+ "path": "design.materials.resetFaces",
4424
+ "namespace": "design.materials",
4425
+ "summary": "Reset specific BREP faces of a component back to the component/type default, removing any per-face finish. The inverse of {@linkcode PluginDesignMaterialsApi.applyToFaces}; undoable when `save` is true (the default). BREP-only (see `applyToFaces`).",
4426
+ "examplePrompts": [
4427
+ "Remove the paint from the top face of this slab",
4428
+ "Reset faces 0 and 2 of this wall to their default material",
4429
+ "Clear the custom finish on the front face of this column\n\n# Example\n```ts\nconst [wall] = await snaptrude.design.query.listWalls({ storeys: [1] })\nconst { count } = await snaptrude.design.materials.resetFaces(wall, [0, 1])\nconsole.log(\"reset\", count, \"faces\")\n```"
4430
+ ],
4431
+ "argsType": "ComponentHandle",
4432
+ "resultType": "PluginMaterialResult"
4433
+ },
3237
4434
  {
3238
4435
  "path": "design.query.exists",
3239
4436
  "namespace": "design.query",
@@ -3368,10 +4565,11 @@
3368
4565
  {
3369
4566
  "path": "design.query.getProperties",
3370
4567
  "namespace": "design.query",
3371
- "summary": "Read an entity's common properties as a {@linkcode PluginEntityProperties} record (only applicable fields are present). For spaces/masses this includes `adjacency` — the per-entity adjacency read (bulk form: `program.adjacency.getMatrix`).",
4568
+ "summary": "Read an entity's common properties as a {@linkcode PluginEntityProperties} record (only applicable fields are present). For spaces/masses this includes `adjacency` — the per-entity adjacency read (bulk form: `program.adjacency.getMatrix`). For walls and the slab family (slab / floor / roof / ceiling) this includes `buildingType` — the assigned building type NAME the panel's type dropdown shows, matching `design.types.list(kind)`.",
3372
4569
  "examplePrompts": [
3373
4570
  "Show me all the details of the selected object",
3374
4571
  "What storey is this wall on?",
4572
+ "Which wall type is assigned to this wall?",
3375
4573
  "Which department does this room belong to?",
3376
4574
  "Is this element locked or hidden?",
3377
4575
  "Get the adjacencies of this space\n\n# Example\n```ts\nconst [wall] = await snaptrude.design.query.listWalls()\nconst props = await snaptrude.design.query.getProperties(wall)\nconsole.log(props.type, props.storey, props.boundingBox)\n\n// The record is partial — type-specific fields exist only where they apply\nconst [room] = await snaptrude.design.query.listSpaces()\nconst p = await snaptrude.design.query.getProperties(room)\nif (p.spaceType === \"Room\" && p.areaClass === \"NET\") {\nfor (const adj of p.adjacency ?? []) {\n// adj.value: 2 = direct, 1 = indirect/contact, -1 = restricted\nconsole.log(adj.spaceId, adj.value)\n}\n}\n```"
@@ -3379,6 +4577,19 @@
3379
4577
  "argsType": "ComponentHandle",
3380
4578
  "resultType": "PluginEntityProperties"
3381
4579
  },
4580
+ {
4581
+ "path": "design.query.getStaircaseParams",
4582
+ "namespace": "design.query",
4583
+ "summary": "Read a staircase's parametric properties — its preset, dimensions, step count, base offset, and height-lock state — as a {@linkcode PluginStaircaseParams} record. The paired write is `design.update.staircase`.",
4584
+ "examplePrompts": [
4585
+ "What's the riser height of this staircase?",
4586
+ "How many steps does the selected stair have?",
4587
+ "Show me the tread and width of this staircase",
4588
+ "Read all the parameters of the stairs on level 1\n\n# Example\n```ts\nconst [stair] = await snaptrude.design.query.listStaircases({ isSelected: true })\nconst params = stair ? await snaptrude.design.query.getStaircaseParams(stair) : null\nif (params) console.log(params.steps, params.riser, params.tread)\n```"
4589
+ ],
4590
+ "argsType": "ComponentHandle",
4591
+ "resultType": "PluginStaircaseParams | null"
4592
+ },
3382
4593
  {
3383
4594
  "path": "design.query.listBeams",
3384
4595
  "namespace": "design.query",
@@ -3623,9 +4834,11 @@
3623
4834
  "examplePrompts": [
3624
4835
  "What's the area of this room?",
3625
4836
  "How long is the selected wall?",
4837
+ "How thick is this wall?",
4838
+ "Get the thickness of the slab on level 2",
3626
4839
  "Get the volume of this mass",
3627
4840
  "Give me the dimensions of the selected element",
3628
- "What's the floor area of the kitchen?\n\n# Example\n```ts\nconst [space] = await snaptrude.design.query.listSpaces()\nconst m = await snaptrude.design.query.measure(space)\nconsole.log(m?.area, m?.volume)\n```"
4841
+ "What's the floor area of the kitchen?\n\n# Example\n```ts\nconst [space] = await snaptrude.design.query.listSpaces()\nconst m = await snaptrude.design.query.measure(space)\nconsole.log(m?.area, m?.volume)\n\n// wall dimensions — the panel's Thickness / Height, in engine units\nconst [wall] = await snaptrude.design.query.listWalls()\nconst wm = await snaptrude.design.query.measure(wall)\nconsole.log(wm?.thickness, wm?.height)\n```"
3629
4842
  ],
3630
4843
  "argsType": "ComponentHandle",
3631
4844
  "resultType": "PluginEntityMeasurements | null"
@@ -3724,43 +4937,228 @@
3724
4937
  "resultType": "PluginDesignChangeResult"
3725
4938
  },
3726
4939
  {
3727
- "path": "design.transform.move",
3728
- "namespace": "design.transform",
3729
- "summary": "Translate entities by a **relative** displacement vector (added to the first component's absolute position as the anchor). Undoable.",
4940
+ "path": "design.selection.setByFilter",
4941
+ "namespace": "design.selection",
4942
+ "summary": "Replace the selection with every visible entity of the active building that matches the filter — the programmatic equivalent of the editor's **Story selection** (`storeys`) and **Filter selection** (`types`) menus under the select tool, including their combination (fields AND, values within a field OR). Reaches selection-only kinds the query surface cannot (sites, terrain, CAD/PDF/image imports, dimension lines, 3D models, neighborhood buildings) and selects whole groups the way the editor does.",
4943
+ "examplePrompts": [
4944
+ "Select everything on storey 2",
4945
+ "Select all the walls and doors",
4946
+ "Story selection: select the ground floor and first floor",
4947
+ "Filter selection: select all furniture in the model",
4948
+ "Select only the furniture on the second storey",
4949
+ "Select all the spaces so I can recolor them\n\n# Example\n```ts\n// \"Story selection\": everything on storeys 1 and 2\nawait snaptrude.design.selection.setByFilter({ storeys: [1, 2] })\n\n// \"Filter selection\": all walls and doors\nawait snaptrude.design.selection.setByFilter({ types: [\"wall\", \"door\"] })\n\n// Combined: only the furniture on storey 2\nconst { affected } = await snaptrude.design.selection.setByFilter({\nstoreys: [2],\ntypes: [\"furniture\"],\n})\n```"
4950
+ ],
4951
+ "argsType": "PluginSelectionFilter",
4952
+ "resultType": "PluginDesignChangeResult"
4953
+ },
4954
+ {
4955
+ "path": "design.transform.align",
4956
+ "namespace": "design.transform",
4957
+ "summary": "Align a set of components by snapping one bounding-box edge to a common value — the classic Left/Center/Right/Top/Middle/Bottom align. Purely **world-axis** (deterministic and headless — the UI's camera-relative remap is bypassed):",
4958
+ "examplePrompts": [
4959
+ "Align the selected rooms to the left",
4960
+ "Line up these masses along their top edges",
4961
+ "Center these columns horizontally",
4962
+ "Align all the walls to the left edge of this reference wall",
4963
+ "Snap the bottom edges of these spaces together\n\n# Example\n```ts\nconst rooms = await snaptrude.design.selection.get()\n// align every room's left (world -X) edge to a common minimum\nawait snaptrude.design.transform.align(rooms, \"left\")\n// …or align them to a fixed reference component's left edge\nconst [anchor] = await snaptrude.design.query.listWalls({ storeys: [1] })\nawait snaptrude.design.transform.align(rooms, \"left\", { reference: anchor })\n```"
4964
+ ],
4965
+ "argsType": "ComponentHandle[]",
4966
+ "resultType": "PluginDesignChangeResult"
4967
+ },
4968
+ {
4969
+ "path": "design.transform.mirror",
4970
+ "namespace": "design.transform",
4971
+ "summary": "Mirror components **in place** about a horizontal axis, flipping their geometry across that axis through the combined bounding-box centre (the mesh's world-matrix flip + brep inversion + CAD/dimension-line/parametric handling commit atomically). Nothing moves off-centre — this is the toolbar \"flip\", not a translate-and-reflect. Undoable.",
4972
+ "examplePrompts": [
4973
+ "Mirror the selected building across the x axis",
4974
+ "Flip these rooms left to right",
4975
+ "Mirror this furniture block horizontally",
4976
+ "Flip the selected walls front to back",
4977
+ "Create a mirror image of these masses about the z axis\n\n# Example\n```ts\nconst rooms = await snaptrude.design.selection.get()\nawait snaptrude.design.transform.mirror(rooms, \"x\")\n```"
4978
+ ],
4979
+ "argsType": "ComponentHandle[]",
4980
+ "resultType": "PluginDesignChangeResult"
4981
+ },
4982
+ {
4983
+ "path": "design.transform.move",
4984
+ "namespace": "design.transform",
4985
+ "summary": "Translate entities by a **relative** displacement vector (added to the first component's absolute position as the anchor). Undoable.",
4986
+ "examplePrompts": [
4987
+ "Move the selected room 5 metres to the right",
4988
+ "Shift these walls 3m along the x axis",
4989
+ "Nudge this space 500mm north",
4990
+ "Translate the furniture block by (10, 0, 5)",
4991
+ "Move these masses up one storey\n\n# Example\n```ts\nconst { vec3 } = snaptrude.core.math\nawait snaptrude.design.transform.move([\"space-id\"], vec3.new(10, 0, 0))\n```"
4992
+ ],
4993
+ "argsType": "ComponentHandle[]",
4994
+ "resultType": "PluginDesignChangeResult"
4995
+ },
4996
+ {
4997
+ "path": "design.transform.rotate",
4998
+ "namespace": "design.transform",
4999
+ "summary": "Rotate entities by a **signed angle in DEGREES** (positive = CCW about +Y). The pivot defaults to the combined bounding-box centre; pass `options.pivot` to rotate about an explicit world-space point instead. NOTE: unlike the removed `tools.transform.rotate` (radians), this canonical form takes DEGREES. Undoable.",
5000
+ "examplePrompts": [
5001
+ "Rotate the selected building 90 degrees",
5002
+ "Turn this room 45 degrees clockwise",
5003
+ "Spin the furniture block 180 degrees about its centre",
5004
+ "Rotate these masses 30 degrees around the vertical axis",
5005
+ "Rotate these walls 90 degrees about the origin\n\n# Example\n```ts\nawait snaptrude.design.transform.rotate([\"space-id\"], 90)\n// …or rotate about an explicit pivot point\nconst { vec3 } = snaptrude.core.math\nawait snaptrude.design.transform.rotate([\"space-id\"], 90, { pivot: vec3.new(0, 0, 0) })\n```"
5006
+ ],
5007
+ "argsType": "ComponentHandle[]",
5008
+ "resultType": "PluginDesignChangeResult"
5009
+ },
5010
+ {
5011
+ "path": "design.types.get",
5012
+ "namespace": "design.types",
5013
+ "summary": "Get one building type by its `\"<kind>:<name>\"` id — its labelled layer stack (each layer's role, thickness and material) plus the summed total thickness.",
5014
+ "examplePrompts": [
5015
+ "What layers make up this wall type?",
5016
+ "Show the construction of the exposed-concrete wall",
5017
+ "What's the total thickness of this slab type?",
5018
+ "Which materials are in this roof assembly?\n\n# Example\n```ts\nconst [first] = await snaptrude.design.types.list(\"wall\")\nconst type = await snaptrude.design.types.get(first.id)\nif (type) for (const layer of type.layers) console.log(layer.name, layer.thickness)\n```"
5019
+ ],
5020
+ "argsType": "string",
5021
+ "resultType": "PluginBuildingType | null"
5022
+ },
5023
+ {
5024
+ "path": "design.types.list",
5025
+ "namespace": "design.types",
5026
+ "summary": "List the building types of one `kind` (wall / slab / floor / ceiling / roof) — the built-in defaults plus any team/user-added types. Returns lightweight summaries; call {@linkcode PluginDesignTypesApi.get} for the full layer stack.",
5027
+ "examplePrompts": [
5028
+ "What wall types does this project have?",
5029
+ "List the available slab assemblies",
5030
+ "Show me every roof type in the project",
5031
+ "Which floor types can I use?\n\n# Example\n```ts\nconst wallTypes = await snaptrude.design.types.list(\"wall\")\nfor (const t of wallTypes) console.log(t.id, t.label, t.thickness)\n```"
5032
+ ],
5033
+ "argsType": "PluginBuildingTypeKind",
5034
+ "resultType": "PluginBuildingTypeSummary[]"
5035
+ },
5036
+ {
5037
+ "path": "design.unlock",
5038
+ "namespace": "design",
5039
+ "summary": "Unlock previously locked entities so they can be edited again. Undoable. Paired with {@linkcode PluginDesignApi.lock}.",
5040
+ "examplePrompts": [
5041
+ "Unlock the selected objects",
5042
+ "Make this locked wall editable again",
5043
+ "Unfreeze the masses I locked earlier",
5044
+ "Remove the lock from these doors\n\n# Example\n```ts\n// Unlock everything that is explicitly locked\nconst locked = await snaptrude.design.listLocked()\nconst { affected } = await snaptrude.design.unlock(locked)\n```"
5045
+ ],
5046
+ "argsType": "ComponentHandle[]",
5047
+ "resultType": "PluginDesignChangeResult"
5048
+ },
5049
+ {
5050
+ "path": "design.unlockArea",
5051
+ "namespace": "design",
5052
+ "summary": "Unlock the footprint area of previously area-locked spaces so their area can change again. Paired with {@linkcode PluginDesignApi.lockArea}; cascades to instances + source; undoable. Requires the `area_lock` feature (throws if off).",
5053
+ "examplePrompts": [
5054
+ "Unlock the area of the selected rooms",
5055
+ "Remove the footprint-area lock from this department",
5056
+ "Let me resize this space again by unlocking its area",
5057
+ "Area-unlock everything I locked earlier\n\n# Example\n```ts\nconst locked = await snaptrude.design.listAreaLocked()\nconst { affected } = await snaptrude.design.unlockArea(locked)\n```"
5058
+ ],
5059
+ "argsType": "ComponentHandle[]",
5060
+ "resultType": "PluginDesignChangeResult"
5061
+ },
5062
+ {
5063
+ "path": "design.update.ceiling",
5064
+ "namespace": "design.update",
5065
+ "summary": "Edit a **ceiling's** thickness — the slab-family updater for ceilings (shares the slab thickness command). Undoable. Thickness is in **engine units** (the `design.doors.setWidth` convention) and must be `> 0`. Ceilings have no Overhang control, so `overhang` is rejected with `PRECONDITION_FAILED`.",
5066
+ "examplePrompts": [
5067
+ "Make this ceiling 150mm thick",
5068
+ "Set every ceiling to a 100 thickness",
5069
+ "Thicken the ceiling to 200\n\n# Example\n```ts\nconst [ceiling] = await snaptrude.design.query.listCeilings()\nawait snaptrude.design.update.ceiling(ceiling, { thickness: 150 })\n```"
5070
+ ],
5071
+ "argsType": "ComponentHandle",
5072
+ "resultType": "PluginDesignChangeResult"
5073
+ },
5074
+ {
5075
+ "path": "design.update.floor",
5076
+ "namespace": "design.update",
5077
+ "summary": "Edit a **floor's** thickness — the slab-family updater for floors (shares the slab thickness command). Undoable. Thickness is in **engine units** (the `design.doors.setWidth` convention) and must be `> 0`. Floors have no Overhang control, so `overhang` is rejected with `PRECONDITION_FAILED`.",
5078
+ "examplePrompts": [
5079
+ "Make this floor 200mm thick",
5080
+ "Set every floor to a 250 thickness",
5081
+ "Thicken the ground floor slab to 300\n\n# Example\n```ts\nconst [floor] = await snaptrude.design.query.listFloors()\nawait snaptrude.design.update.floor(floor, { thickness: 200 })\n```"
5082
+ ],
5083
+ "argsType": "ComponentHandle",
5084
+ "resultType": "PluginDesignChangeResult"
5085
+ },
5086
+ {
5087
+ "path": "design.update.roof",
5088
+ "namespace": "design.update",
5089
+ "summary": "Edit a **roof's** thickness and/or overhang — the same commands the roof panel's Thickness field and Overhang slider drive (shares the slab-family machinery). Sparse: only the fields you provide change. Undoable. Both values are in **engine units** (the `design.doors.setWidth` convention); thickness must be `> 0`, overhang is an absolute offset (negative insets the roof) and re-applying the current overhang is a no-op.",
5090
+ "examplePrompts": [
5091
+ "Make this roof 300mm thick",
5092
+ "Set the roof slab thickness to 250",
5093
+ "Give the roof a 600 overhang",
5094
+ "Pull the roof overhang back to 0\n\n# Example\n```ts\nconst [roof] = await snaptrude.design.query.listRoofs()\nawait snaptrude.design.update.roof(roof, { overhang: 600 })\n```"
5095
+ ],
5096
+ "argsType": "ComponentHandle",
5097
+ "resultType": "PluginDesignChangeResult"
5098
+ },
5099
+ {
5100
+ "path": "design.update.setBaseOffset",
5101
+ "namespace": "design.update",
5102
+ "summary": "Set a component's **base offset** — its vertical distance above its own storey's base level. Moves the component so its base lands at `storeyBase + offset`, composed over the same command-backed move machinery as {@linkcode setElevation} (undoable, persisted, per-type invariants kept in sync). Use this instead of {@linkcode setElevation} when you want an offset relative to the storey rather than an absolute world height. `offset` is in **engine units** (the `design.doors.setWidth` convention); `0` sits the base flush with the storey base. Re-applying the current offset is a no-op.",
5103
+ "examplePrompts": [
5104
+ "Lift this element 300 above its floor",
5105
+ "Set this staircase's base offset to 0",
5106
+ "Raise the selected mass 500 off the storey base",
5107
+ "Offset this slab 150 above the floor level\n\n# Example\n```ts\nconst [stair] = await snaptrude.design.query.listStaircases()\nawait snaptrude.design.update.setBaseOffset(stair, 0)\n```"
5108
+ ],
5109
+ "argsType": "ComponentHandle",
5110
+ "resultType": "PluginDesignChangeResult"
5111
+ },
5112
+ {
5113
+ "path": "design.update.setElevation",
5114
+ "namespace": "design.update",
5115
+ "summary": "Set a component's **absolute world elevation** — moves it vertically so its base (the bounding-box bottom, world Y) lands at `elevation`. Composed over the canonical command-backed move machinery, so it is undoable and persisted exactly like dragging the element up or down; per-type invariants (e.g. a staircase's base offset) stay in sync. `elevation` is in **engine units** (the `design.doors.setWidth` convention). Re-applying the current elevation is a no-op.",
5116
+ "examplePrompts": [
5117
+ "Set this element's elevation to 3000",
5118
+ "Raise this mass so its base sits at 3 metres",
5119
+ "Drop the selected slab to elevation 0",
5120
+ "Put this staircase's base at 3200\n\n# Example\n```ts\n// Sit the roof slab exactly at the top of a 3m storey\nconst [roof] = await snaptrude.design.query.listRoofs()\nawait snaptrude.design.update.setElevation(roof, 3000)\n```"
5121
+ ],
5122
+ "argsType": "ComponentHandle",
5123
+ "resultType": "PluginDesignChangeResult"
5124
+ },
5125
+ {
5126
+ "path": "design.update.setLabel",
5127
+ "namespace": "design.update",
5128
+ "summary": "Set a component's **Label** — the same editable Label field the properties panel shows (doors, windows, furniture, spaces, and every other labelled component). The paired read is `design.query.getLabel`. Undoable; the canvas label text updates immediately.",
3730
5129
  "examplePrompts": [
3731
- "Move the selected room 5 metres to the right",
3732
- "Shift these walls 3m along the x axis",
3733
- "Nudge this space 500mm north",
3734
- "Translate the furniture block by (10, 0, 5)",
3735
- "Move these masses up one storey\n\n# Example\n```ts\nconst { vec3 } = snaptrude.core.math\nawait snaptrude.design.transform.move([\"space-id\"], vec3.new(10, 0, 0))\n```"
5130
+ "Rename this door to D-101",
5131
+ "Number all doors on storey 2 with a D-2-XX tag",
5132
+ "Set the selected window's label to W-04",
5133
+ "Tag every door with its fire rating\n\n# Example\n```ts\n// Door tag numbering: label every door as D-<storey>-<n>, numbered per storey\nawait snaptrude.design.selection.setByFilter({ types: [\"door\"] })\nconst doors = await snaptrude.design.selection.get()\nconst counts = {}\nfor (const door of doors) {\nconst { storey = 0 } = await snaptrude.design.query.getProperties(door)\ncounts[storey] = (counts[storey] ?? 0) + 1\nawait snaptrude.design.update.setLabel(door, `D-${storey}-${String(counts[storey]).padStart(2, \"0\")}`)\n}\n```"
3736
5134
  ],
3737
- "argsType": "ComponentHandle[]",
3738
- "resultType": "PluginDesignChangeResult"
5135
+ "argsType": "ComponentHandle",
5136
+ "resultType": "boolean"
3739
5137
  },
3740
5138
  {
3741
- "path": "design.transform.rotate",
3742
- "namespace": "design.transform",
3743
- "summary": "Rotate entities by a **signed angle in DEGREES**, anchored at the combined bounding-box centre (positive = CCW about +Y). NOTE: unlike the removed `tools.transform.rotate` (radians + caller pivot), this canonical form takes DEGREES and has NO caller pivot the pivot is always the bbox centre. Undoable.",
5139
+ "path": "design.update.setStorey",
5140
+ "namespace": "design.update",
5141
+ "summary": "Reassign one or more components to another **storey** the same operation as the properties panel's Story dropdown, and it works across element kinds exactly like the panel (walls, slabs, masses, furniture, staircases, ...). Each component is moved vertically to the target storey's level (per-kind placement rules — e.g. a slab sits at the storey base, a wall on it) and its storey assignment, children, and dimension lines update together as **one undoable operation**.",
3744
5142
  "examplePrompts": [
3745
- "Rotate the selected building 90 degrees",
3746
- "Turn this room 45 degrees clockwise",
3747
- "Spin the furniture block 180 degrees about its centre",
3748
- "Rotate these masses 30 degrees around the vertical axis\n\n# Example\n```ts\nawait snaptrude.design.transform.rotate([\"space-id\"], 90)\n```"
5143
+ "Move this sofa to storey 2",
5144
+ "Put the selected walls on the first basement level",
5145
+ "Send everything on this storey up one level",
5146
+ "Reassign these slabs to storey 3\n\n# Example\n```ts\n// Move the current selection up to storey 2\nconst selection = await snaptrude.design.selection.get()\nconst { affected } = await snaptrude.design.update.setStorey(selection, 2)\nconsole.log(\"moved\", affected.length, \"components\")\n```"
3749
5147
  ],
3750
5148
  "argsType": "ComponentHandle[]",
3751
5149
  "resultType": "PluginDesignChangeResult"
3752
5150
  },
3753
5151
  {
3754
- "path": "design.unlock",
3755
- "namespace": "design",
3756
- "summary": "Unlock previously locked entities so they can be edited again. Undoable. Paired with {@linkcode PluginDesignApi.lock}.",
5152
+ "path": "design.update.slab",
5153
+ "namespace": "design.update",
5154
+ "summary": "Edit a **slab's** thickness and/or overhang the same commands the properties panel's Thickness field and Overhang slider drive. Sparse: only the fields you provide change. Undoable; the slab rebuilds and dimension lines refresh. Both values are in **engine units** (the same convention as `design.doors.setWidth`); thickness must be `> 0`, overhang is an absolute offset (negative insets the slab) and re-applying the current overhang is a no-op.",
3757
5155
  "examplePrompts": [
3758
- "Unlock the selected objects",
3759
- "Make this locked wall editable again",
3760
- "Unfreeze the masses I locked earlier",
3761
- "Remove the lock from these doors\n\n# Example\n```ts\n// Unlock everything that is explicitly locked\nconst locked = await snaptrude.design.listLocked()\nconst { affected } = await snaptrude.design.unlock(locked)\n```"
5156
+ "Set this slab's thickness to 250mm",
5157
+ "Make the floor slab 300 thick",
5158
+ "Give this slab a 200 overhang",
5159
+ "Remove the overhang on every slab on level 2\n\n# Example\n```ts\nconst [slab] = await snaptrude.design.query.listSlabs()\nawait snaptrude.design.update.slab(slab, { thickness: 250, overhang: 200 })\n```"
3762
5160
  ],
3763
- "argsType": "ComponentHandle[]",
5161
+ "argsType": "ComponentHandle",
3764
5162
  "resultType": "PluginDesignChangeResult"
3765
5163
  },
3766
5164
  {
@@ -3791,6 +5189,99 @@
3791
5189
  "argsType": "PluginUpdateSpaceItem[]",
3792
5190
  "resultType": "PluginSpaceUpdateResult[]"
3793
5191
  },
5192
+ {
5193
+ "path": "design.update.staircase",
5194
+ "namespace": "design.update",
5195
+ "summary": "Update the parameters of one or more staircases — riser, tread, width, depth, step count, total height, well size, landing depth, base offset, and the two height locks — in one undoable operation. Sparse: only the fields you provide change. The paired read is `design.query.getStaircaseParams`.",
5196
+ "examplePrompts": [
5197
+ "Set the riser of this staircase to 165mm",
5198
+ "Change all the stairs to 14 steps",
5199
+ "Make the selected staircase 1200 wide with a 280 tread",
5200
+ "Widen every staircase on level 1 to 1 metre",
5201
+ "Unlock the height and set this stair to 3200 tall\n\n# Example\n```ts\n// Give every ground-floor staircase a common riser + tread (engine units)\nconst stairs = await snaptrude.design.query.listStaircases({ storeys: [1] })\nconst { affected } = await snaptrude.design.update.staircase(stairs, {\nriser: 165,\ntread: 280,\n})\nconsole.log(\"updated\", affected.length, \"staircases\")\n```"
5202
+ ],
5203
+ "argsType": "ComponentHandle[]",
5204
+ "resultType": "PluginDesignChangeResult"
5205
+ },
5206
+ {
5207
+ "path": "design.update.wall",
5208
+ "namespace": "design.update",
5209
+ "summary": "Edit a **wall** — its thickness and/or height (the same command the properties panel's Thickness/Height fields drive) and/or its **wall type** (the panel's Wall Types dropdown: converts the wall to another type, rebuilding its layer stack and materials). Sparse: only the fields you provide change. Undoable; the geometry rebuilds and any dimension lines refresh. Stacked-wall companions and hosted fenestration are handled exactly as the panel does.",
5210
+ "examplePrompts": [
5211
+ "Make this wall 230mm thick",
5212
+ "Set the selected wall's height to 3 metres",
5213
+ "Thicken every exterior wall to 300",
5214
+ "Change this wall to a Glass Wall",
5215
+ "Convert all the partitions on this floor to Brick Wall\n\n# Example\n```ts\n// Convert every wall on storey 1 to the first listed wall type\nconst [wallType] = await snaptrude.design.types.list(\"wall\")\nconst walls = await snaptrude.design.query.listWalls({ storeys: [1] })\nfor (const wall of walls) {\nawait snaptrude.design.update.wall(wall, { type: wallType.id })\n}\n```"
5216
+ ],
5217
+ "argsType": "ComponentHandle",
5218
+ "resultType": "PluginDesignChangeResult"
5219
+ },
5220
+ {
5221
+ "path": "design.visibility.hide",
5222
+ "namespace": "design.visibility",
5223
+ "summary": "Hide entities from the viewport — the same as the \"Hide\" action. Undoable. Hosted door/window/void children ride along with their wall. Already-hidden entities stay hidden.",
5224
+ "examplePrompts": [
5225
+ "Hide the selected walls",
5226
+ "Conceal these masses so I can see behind them",
5227
+ "Hide every column on this floor",
5228
+ "Make this furniture disappear from view\n\n# Example\n```ts\nconst walls = await snaptrude.design.query.listWalls({ storeys: [1] })\nconst { affected } = await snaptrude.design.visibility.hide(walls)\n```"
5229
+ ],
5230
+ "argsType": "ComponentHandle[]",
5231
+ "resultType": "PluginDesignChangeResult"
5232
+ },
5233
+ {
5234
+ "path": "design.visibility.isolate",
5235
+ "namespace": "design.visibility",
5236
+ "summary": "Isolate entities — hide everything else so only the given entities remain visible (the \"Isolate\" / solo action). Undoable. Reverse it with {@linkcode PluginDesignVisibilityApi.showAll}.",
5237
+ "examplePrompts": [
5238
+ "Isolate the selected room so I can focus on it",
5239
+ "Show only these walls and hide the rest",
5240
+ "Solo this mass",
5241
+ "Hide everything except the staircase\n\n# Example\n```ts\nconst [room] = await snaptrude.design.selection.get()\nawait snaptrude.design.visibility.isolate([room])\n```"
5242
+ ],
5243
+ "argsType": "ComponentHandle[]",
5244
+ "resultType": "PluginDesignChangeResult"
5245
+ },
5246
+ {
5247
+ "path": "design.visibility.showAll",
5248
+ "namespace": "design.visibility",
5249
+ "summary": "Reveal everything hidden on the active story — the \"Show All\" action, which also exits an isolate. Undoable.",
5250
+ "examplePrompts": [
5251
+ "Show everything again",
5252
+ "Unhide all the hidden objects",
5253
+ "Exit isolate mode",
5254
+ "Reveal everything I hid earlier\n\n# Example\n```ts\nconst { affected } = await snaptrude.design.visibility.showAll()\nconsole.log(`Revealed ${affected.length} entities`)\n```"
5255
+ ],
5256
+ "argsType": null,
5257
+ "resultType": "PluginDesignChangeResult"
5258
+ },
5259
+ {
5260
+ "path": "design.windows.exists",
5261
+ "namespace": "design.windows",
5262
+ "summary": "Test whether a window catalog item exists for the given library id.",
5263
+ "examplePrompts": [
5264
+ "Is this window still in the library?",
5265
+ "Check whether a window catalog item with this id exists",
5266
+ "Does my team library have this window?",
5267
+ "Verify the window is available before placing it\n\n# Example\n```ts\nconst [entry] = await snaptrude.design.windows.listCatalog()\nconst stillAvailable = await snaptrude.design.windows.exists(entry.id)\nconsole.log(stillAvailable ? \"safe to place\" : \"removed from library\")\n```"
5268
+ ],
5269
+ "argsType": "string",
5270
+ "resultType": "boolean"
5271
+ },
5272
+ {
5273
+ "path": "design.windows.getCatalogItem",
5274
+ "namespace": "design.windows",
5275
+ "summary": "Get a single window catalog item by its library id.",
5276
+ "examplePrompts": [
5277
+ "Get the details of this window from the library",
5278
+ "Look up the catalog entry for this window id",
5279
+ "What is the cost of this window item?",
5280
+ "Show me the family name of this window in the catalog\n\n# Example\n```ts\nconst [entry] = await snaptrude.design.windows.listCatalog()\nconst item = await snaptrude.design.windows.getCatalogItem(entry.id)\nif (item) console.log(item.name, item.source, item.dbType)\n```"
5281
+ ],
5282
+ "argsType": "string",
5283
+ "resultType": "PluginObjectCatalogItem | null"
5284
+ },
3794
5285
  {
3795
5286
  "path": "design.windows.getDimensions",
3796
5287
  "namespace": "design.windows",
@@ -3844,6 +5335,32 @@
3844
5335
  "argsType": "ComponentHandle",
3845
5336
  "resultType": "number | null"
3846
5337
  },
5338
+ {
5339
+ "path": "design.windows.listCatalog",
5340
+ "namespace": "design.windows",
5341
+ "summary": "List the placeable window catalog (team + general libraries), optionally restricted to one group by its `dbType` token.",
5342
+ "examplePrompts": [
5343
+ "What windows can I place in this project?",
5344
+ "List every window in the library",
5345
+ "Show me the casement windows I can add",
5346
+ "Browse the window catalog\n\n# Example\n```ts\nconst [group] = await snaptrude.design.windows.listCatalogGroups()\nconst items = await snaptrude.design.windows.listCatalog(group?.dbType)\nfor (const item of items) console.log(item.id, item.name, item.thumbnailUrl)\n```"
5347
+ ],
5348
+ "argsType": "string",
5349
+ "resultType": "PluginObjectCatalogItem[]"
5350
+ },
5351
+ {
5352
+ "path": "design.windows.listCatalogGroups",
5353
+ "namespace": "design.windows",
5354
+ "summary": "List the window catalog **groups** — the placement families (Fixed, Casement, Sliding, Folding, …), built-in groups merged with any team-custom types.",
5355
+ "examplePrompts": [
5356
+ "What kinds of windows can I place?",
5357
+ "List the window groups in the catalog",
5358
+ "Show me the window families available in this project",
5359
+ "Which window types does this project support?\n\n# Example\n```ts\nconst groups = await snaptrude.design.windows.listCatalogGroups()\nfor (const g of groups) console.log(g.dbType, g.label, g.source)\n```"
5360
+ ],
5361
+ "argsType": null,
5362
+ "resultType": "PluginObjectCatalogGroup[]"
5363
+ },
3847
5364
  {
3848
5365
  "path": "design.windows.setHeight",
3849
5366
  "namespace": "design.windows",
@@ -3965,6 +5482,32 @@
3965
5482
  "argsType": "number",
3966
5483
  "resultType": "PluginStoryCreateResult"
3967
5484
  },
5485
+ {
5486
+ "path": "entity.story.delete",
5487
+ "namespace": "entity.story",
5488
+ "summary": "Delete a story and everything on it — the same as removing it from the storey panel. Every element placed on the story (walls, floors, masses, …) is deleted with it, the remaining stories are re-stacked, and the active story falls back to an adjacent one. Committed as a single undo step.",
5489
+ "examplePrompts": [
5490
+ "Delete the top floor",
5491
+ "Remove the basement level",
5492
+ "Get rid of storey 3",
5493
+ "Delete the second floor and everything on it\n\n# Example\n```ts\nconst { newActiveStory } = await snaptrude.entity.story.delete(3)\nconsole.log(`Deleted story 3; now on story ${newActiveStory}`)\n```"
5494
+ ],
5495
+ "argsType": "number",
5496
+ "resultType": "PluginStoryDeleteResult"
5497
+ },
5498
+ {
5499
+ "path": "entity.story.duplicate",
5500
+ "namespace": "entity.story",
5501
+ "summary": "Duplicate a story into the adjacent level, up or down.",
5502
+ "examplePrompts": [
5503
+ "Duplicate this floor to the storey above",
5504
+ "Copy the ground floor down into a new basement",
5505
+ "Repeat this level upwards with its own independent geometry",
5506
+ "Duplicate just the selected walls onto the next floor up\n\n# Example\n```ts\n// Duplicate the whole active story one level up (instanced copies).\nconst { targetStories, created, skipped } =\nawait snaptrude.entity.story.duplicate(\"up\")\nconsole.log(`Copied ${created.length} elements onto story ${targetStories}`)\nif (skipped) console.log(`${skipped} elements were skipped`)\n```"
5507
+ ],
5508
+ "argsType": "\"up\" | \"down\"",
5509
+ "resultType": "PluginStoryDuplicateResult"
5510
+ },
3968
5511
  {
3969
5512
  "path": "entity.story.get",
3970
5513
  "namespace": "entity.story",
@@ -3992,15 +5535,29 @@
3992
5535
  "argsType": null,
3993
5536
  "resultType": "PluginStoryGetAllResult"
3994
5537
  },
5538
+ {
5539
+ "path": "entity.story.setActive",
5540
+ "namespace": "entity.story",
5541
+ "summary": "Make a story the active story — the same as clicking it in the storey/layer panel. Subsequent draws and creates target this story, and in 2D the viewport switches to it. This is a view/navigation change: it is **not** undoable and commits nothing to the model.",
5542
+ "examplePrompts": [
5543
+ "Switch to the second floor",
5544
+ "Make the ground storey active",
5545
+ "Go to the basement level",
5546
+ "Set level 3 as the current storey\n\n# Example\n```ts\n// Activate story 2, then draw a wall — it lands on story 2.\nawait snaptrude.entity.story.setActive(2)\n```"
5547
+ ],
5548
+ "argsType": "number",
5549
+ "resultType": "PluginStorySetActiveResult"
5550
+ },
3995
5551
  {
3996
5552
  "path": "entity.story.update",
3997
5553
  "namespace": "entity.story",
3998
- "summary": "Update a story's height.",
5554
+ "summary": "Update a story's floor-to-floor `height` and/or `name`.",
3999
5555
  "examplePrompts": [
4000
5556
  "Change the ground floor height to 3.5 metres",
4001
5557
  "Make the second storey taller",
5558
+ "Rename the ground floor to \"Lobby\"",
4002
5559
  "Set the floor-to-floor height of level 1",
4003
- "Increase the height of the third floor\n\n# Example\n```ts\n// Set ground floor height to 5 Babylon units\nconst result = await snaptrude.entity.story.update(1, 5)\n```"
5560
+ "Rename storey 2 and make it taller in one go\n\n# Example\n```ts\n// Set ground floor height to 5 Babylon units — walls stretch and the\n// floors above move up to match, all in a single undo step.\nconst result = await snaptrude.entity.story.update(1, 5)\n// Rename only, leaving the height untouched.\nawait snaptrude.entity.story.update(1, undefined, { name: \"Lobby\" })\n```"
4004
5561
  ],
4005
5562
  "argsType": "number",
4006
5563
  "resultType": "PluginStoryUpdateResult"
@@ -4211,6 +5768,67 @@
4211
5768
  "argsType": "PluginAIInspirationSaveRecipeArgs",
4212
5769
  "resultType": "PluginAIInspirationSaveRecipeResult"
4213
5770
  },
5771
+ {
5772
+ "path": "presentation.annotate.arrow",
5773
+ "namespace": "presentation.annotate",
5774
+ "summary": "Draw an arrow on a sheet.",
5775
+ "examplePrompts": [
5776
+ "Draw an arrow pointing at the entrance on Sheet 1",
5777
+ "Add a red arrow from the title to the plan view",
5778
+ "Point an arrow at the top-left view on the cover sheet\n\n# Example\n```ts\nconst { shapeId } = await snaptrude.presentation.annotate.arrow(\n\"sheet_1\",\n{ x: 100, y: 200 },\n{ x: 300, y: 250 },\n{ color: \"red\" },\n)\n```"
5779
+ ],
5780
+ "argsType": "string",
5781
+ "resultType": "PluginPresentationAnnotateResult"
5782
+ },
5783
+ {
5784
+ "path": "presentation.annotate.note",
5785
+ "namespace": "presentation.annotate",
5786
+ "summary": "Add a sticky note to a sheet.",
5787
+ "examplePrompts": [
5788
+ "Add a sticky note \"Review this wall\" to Sheet 1",
5789
+ "Put a yellow note on the cover sheet",
5790
+ "Leave a note next to the ground floor plan\n\n# Example\n```ts\nconst { shapeId } = await snaptrude.presentation.annotate.note(\n\"sheet_1\",\n\"Review this wall\",\n{ position: { x: 60, y: 120 }, color: \"yellow\" },\n)\n```"
5791
+ ],
5792
+ "argsType": "string",
5793
+ "resultType": "PluginPresentationAnnotateResult"
5794
+ },
5795
+ {
5796
+ "path": "presentation.annotate.shape",
5797
+ "namespace": "presentation.annotate",
5798
+ "summary": "Draw a geo shape (rectangle, ellipse, cloud, …) on a sheet.",
5799
+ "examplePrompts": [
5800
+ "Draw a revision cloud around the kitchen on Sheet 2",
5801
+ "Add a red rectangle highlight to the sheet",
5802
+ "Draw an ellipse around the entrance on the cover sheet\n\n# Example\n```ts\nconst { shapeId } = await snaptrude.presentation.annotate.shape(\n\"sheet_1\",\n\"cloud\",\n{ x: 80, y: 80, w: 240, h: 160 },\n{ color: \"red\" },\n)\n```"
5803
+ ],
5804
+ "argsType": "string",
5805
+ "resultType": "PluginPresentationAnnotateResult"
5806
+ },
5807
+ {
5808
+ "path": "presentation.annotate.text",
5809
+ "namespace": "presentation.annotate",
5810
+ "summary": "Add a text label to a sheet.",
5811
+ "examplePrompts": [
5812
+ "Add a title \"Ground Floor\" to Sheet 1",
5813
+ "Label the cover sheet with the project name",
5814
+ "Caption this view with \"Proposed layout\"",
5815
+ "Put a red note on the sheet\n\n# Example\n```ts\nconst { shapeId } = await snaptrude.presentation.annotate.text(\n\"sheet_1\",\n\"Ground Floor\",\n{ position: { x: 40, y: 40 }, size: \"xl\", color: \"blue\" },\n)\n```"
5816
+ ],
5817
+ "argsType": "string",
5818
+ "resultType": "PluginPresentationAnnotateTextResult"
5819
+ },
5820
+ {
5821
+ "path": "presentation.diagrams.generateProgram",
5822
+ "namespace": "presentation.diagrams",
5823
+ "summary": "Generate the program (space + department) diagrams for the current model, creating new layout sheets.",
5824
+ "examplePrompts": [
5825
+ "Generate the program diagrams for this project",
5826
+ "Auto-generate the space and department diagram sheets",
5827
+ "Create the program layout sheets from the model\n\n# Example\n```ts\nconst { sheetIds } = await snaptrude.presentation.diagrams.generateProgram()\n```"
5828
+ ],
5829
+ "argsType": null,
5830
+ "resultType": "PluginPresentationDiagramsGenerateResult"
5831
+ },
4214
5832
  {
4215
5833
  "path": "presentation.diagrams.place",
4216
5834
  "namespace": "presentation.diagrams",
@@ -4223,6 +5841,20 @@
4223
5841
  "argsType": "string",
4224
5842
  "resultType": "PluginPresentationDiagramsPlaceResult"
4225
5843
  },
5844
+ {
5845
+ "path": "presentation.export",
5846
+ "namespace": "presentation",
5847
+ "summary": "Export the presentation's layout sheets to a downloadable file (PDF / PNG / JPG) and return the encoded bytes as base64. Wraps the Present-mode Export dialog pipeline headlessly. Requires Present mode to be open.",
5848
+ "examplePrompts": [
5849
+ "Export the presentation as a PDF",
5850
+ "Download all sheets as a single PDF",
5851
+ "Export sheet 1 as a PNG",
5852
+ "Save the presentation sheets as JPG images",
5853
+ "Export these sheets to PDF at high resolution\n\n# Example\n```ts\nconst { files } = await snaptrude.presentation.export(\"pdf\")\n```"
5854
+ ],
5855
+ "argsType": "PluginPresentationExportFormat",
5856
+ "resultType": "PluginPresentationExportResult"
5857
+ },
4226
5858
  {
4227
5859
  "path": "presentation.import.image",
4228
5860
  "namespace": "presentation.import",
@@ -4249,18 +5881,44 @@
4249
5881
  "argsType": "{ url?: string; dataUrl?: string }",
4250
5882
  "resultType": "PluginPresentationImportResult"
4251
5883
  },
5884
+ {
5885
+ "path": "presentation.import.svg",
5886
+ "namespace": "presentation.import",
5887
+ "summary": "Import an SVG onto the current Present sheet as a vector asset.",
5888
+ "examplePrompts": [
5889
+ "Import this SVG diagram onto the present canvas",
5890
+ "Add a vector logo to my presentation board",
5891
+ "Place this SVG floor plan on the current sheet as vectors",
5892
+ "Bring a crisp vector graphic into Present mode\n\n# Example\n```ts\nconst { shapeIds } = await snaptrude.presentation.import.svg({\nurl: \"https://example.com/diagram.svg\",\n})\n```"
5893
+ ],
5894
+ "argsType": "{ url?: string; dataUrl?: string }",
5895
+ "resultType": "PluginPresentationImportResult"
5896
+ },
4252
5897
  {
4253
5898
  "path": "presentation.sheets.create",
4254
5899
  "namespace": "presentation.sheets",
4255
5900
  "summary": "Create a new layout sheet.",
4256
5901
  "examplePrompts": [
4257
5902
  "Create a new sheet called Cover",
4258
- "Add a layout sheet",
4259
- "Make a new presentation sheet named Floor Plans\n\n# Example\n```ts\nconst sheet = await snaptrude.presentation.sheets.create(\"Cover\")\n```"
5903
+ "Add an A3 landscape layout sheet",
5904
+ "Make a new ANSI D presentation sheet named Floor Plans",
5905
+ "Create a portrait A4 sheet\n\n# Example\n```ts\nconst sheet = await snaptrude.presentation.sheets.create(\"Cover\", {\nsize: \"ISO_A3\",\norientation: \"landscape\",\n})\n```"
4260
5906
  ],
4261
5907
  "argsType": "string",
4262
5908
  "resultType": "PluginPresentationSheet"
4263
5909
  },
5910
+ {
5911
+ "path": "presentation.sheets.delete",
5912
+ "namespace": "presentation.sheets",
5913
+ "summary": "Delete a layout sheet.",
5914
+ "examplePrompts": [
5915
+ "Delete sheet_2",
5916
+ "Remove the Cover sheet",
5917
+ "Get rid of the last layout sheet\n\n# Example\n```ts\nconst { id } = await snaptrude.presentation.sheets.delete(\"sheet_2\")\n```"
5918
+ ],
5919
+ "argsType": "string",
5920
+ "resultType": "PluginPresentationSheetsDeleteResult"
5921
+ },
4264
5922
  {
4265
5923
  "path": "presentation.sheets.get",
4266
5924
  "namespace": "presentation.sheets",
@@ -4294,11 +5952,73 @@
4294
5952
  "Place the floor plan on Sheet 1",
4295
5953
  "Add this 3D view to the cover sheet",
4296
5954
  "Drop the site plan onto the layout sheet at 100, 200",
4297
- "Put the Ground Floor view on sheet_1\n\n# Example\n```ts\nconst { shapeId } = await snaptrude.presentation.sheets.place(\"sheet_1\", \"view_123\")\n```"
5955
+ "Put the Ground Floor view on sheet_1 at 1:100 scale",
5956
+ "Place the plan on the cover sheet at quarter-inch scale\n\n# Example\n```ts\nconst { shapeId } = await snaptrude.presentation.sheets.place(\"sheet_1\", \"view_123\", {\nscale: 100, // 1:100 (metric project)\n})\n```"
4298
5957
  ],
4299
5958
  "argsType": "string",
4300
5959
  "resultType": "PluginPresentationSheetsPlaceResult"
4301
5960
  },
5961
+ {
5962
+ "path": "presentation.sheets.rename",
5963
+ "namespace": "presentation.sheets",
5964
+ "summary": "Rename a layout sheet.",
5965
+ "examplePrompts": [
5966
+ "Rename sheet_1 to Cover",
5967
+ "Call the first sheet Ground Floor",
5968
+ "Change this sheet's name to Site Plan\n\n# Example\n```ts\nconst sheet = await snaptrude.presentation.sheets.rename(\"sheet_1\", \"Cover\")\n```"
5969
+ ],
5970
+ "argsType": "string",
5971
+ "resultType": "PluginPresentationSheet"
5972
+ },
5973
+ {
5974
+ "path": "presentation.sheets.reorder",
5975
+ "namespace": "presentation.sheets",
5976
+ "summary": "Move a sheet to a new position in the sheet order.",
5977
+ "examplePrompts": [
5978
+ "Move sheet_3 to the front",
5979
+ "Make the Cover sheet the first sheet",
5980
+ "Reorder this sheet to position 2\n\n# Example\n```ts\nconst { sheets } = await snaptrude.presentation.sheets.reorder(\"sheet_3\", 0)\n```"
5981
+ ],
5982
+ "argsType": "string",
5983
+ "resultType": "PluginPresentationSheetsListResult"
5984
+ },
5985
+ {
5986
+ "path": "presentation.sheets.setActive",
5987
+ "namespace": "presentation.sheets",
5988
+ "summary": "Make a sheet the active sheet.",
5989
+ "examplePrompts": [
5990
+ "Go to sheet_1",
5991
+ "Open the Cover sheet",
5992
+ "Switch to the Site Plan sheet\n\n# Example\n```ts\nawait snaptrude.presentation.sheets.setActive(\"sheet_1\")\n```"
5993
+ ],
5994
+ "argsType": "string",
5995
+ "resultType": "PluginPresentationSheet"
5996
+ },
5997
+ {
5998
+ "path": "presentation.sheets.setSize",
5999
+ "namespace": "presentation.sheets",
6000
+ "summary": "Set a sheet's paper size and/or orientation.",
6001
+ "examplePrompts": [
6002
+ "Resize sheet_1 to A1",
6003
+ "Make the cover sheet ANSI B portrait",
6004
+ "Change this sheet to Arch D landscape",
6005
+ "Set the sheet size to A3\n\n# Example\n```ts\nconst sheet = await snaptrude.presentation.sheets.setSize(\"sheet_1\", \"ISO_A1\", \"portrait\")\n```"
6006
+ ],
6007
+ "argsType": "string",
6008
+ "resultType": "PluginPresentationSheet"
6009
+ },
6010
+ {
6011
+ "path": "presentation.sheets.updatePlacedView",
6012
+ "namespace": "presentation.sheets",
6013
+ "summary": "Refresh placed views to the current model state.",
6014
+ "examplePrompts": [
6015
+ "Update all the placed views to the latest model",
6016
+ "Refresh the views on sheet_1",
6017
+ "Re-render the placed views after my edits\n\n# Example\n```ts\nconst { shapeIds } = await snaptrude.presentation.sheets.updatePlacedView()\n```"
6018
+ ],
6019
+ "argsType": "{\n sheetId?: string\n }",
6020
+ "resultType": "PluginPresentationSheetsUpdatePlacedViewResult"
6021
+ },
4302
6022
  {
4303
6023
  "path": "presentation.views.capture",
4304
6024
  "namespace": "presentation.views",
@@ -4320,11 +6040,24 @@
4320
6040
  "Save the current view as Lobby Perspective",
4321
6041
  "Create a new saved view from where I'm looking",
4322
6042
  "Bookmark this camera angle",
4323
- "Save the current 2D plan as a view\n\n# Example\n```ts\nconst view = await snaptrude.presentation.views.create(\"Lobby\")\n```"
6043
+ "Save the current 2D plan as a view",
6044
+ "Save a view on the second storey\n\n# Example\n```ts\nconst view = await snaptrude.presentation.views.create(\"Lobby\")\n// …or capture the view on a specific storey\nconst level2 = await snaptrude.presentation.views.create(\"Level 2\", { storey: 2 })\n```"
4324
6045
  ],
4325
6046
  "argsType": "string",
4326
6047
  "resultType": "PluginPresentationViewsCreateResult"
4327
6048
  },
6049
+ {
6050
+ "path": "presentation.views.delete",
6051
+ "namespace": "presentation.views",
6052
+ "summary": "Delete a saved view.",
6053
+ "examplePrompts": [
6054
+ "Delete the view named Old Draft",
6055
+ "Remove this saved view",
6056
+ "Get rid of the Lobby camera bookmark\n\n# Example\n```ts\nconst { id } = await snaptrude.presentation.views.delete(\"view_123\")\n```"
6057
+ ],
6058
+ "argsType": "string",
6059
+ "resultType": "PluginPresentationViewsDeleteResult"
6060
+ },
4328
6061
  {
4329
6062
  "path": "presentation.views.get",
4330
6063
  "namespace": "presentation.views",
@@ -4349,6 +6082,19 @@
4349
6082
  "argsType": null,
4350
6083
  "resultType": "PluginPresentationViewsGetResult"
4351
6084
  },
6085
+ {
6086
+ "path": "presentation.views.getSettings",
6087
+ "namespace": "presentation.views",
6088
+ "summary": "Read a saved view's display settings (background, color mode, view mode, axis, edges, labels).",
6089
+ "examplePrompts": [
6090
+ "What color mode is the Ground Floor view using?",
6091
+ "Get the display settings for this view",
6092
+ "Does the site plan view show axes and labels?",
6093
+ "Read the background color of the active view\n\n# Example\n```ts\nconst settings = await snaptrude.presentation.views.getSettings(\"view_123\")\nif (settings) console.log(settings.colorMode, settings.backgroundColor)\n```"
6094
+ ],
6095
+ "argsType": "string",
6096
+ "resultType": "PluginPresentationViewsGetSettingsResult"
6097
+ },
4352
6098
  {
4353
6099
  "path": "presentation.views.list",
4354
6100
  "namespace": "presentation.views",
@@ -4363,6 +6109,18 @@
4363
6109
  "argsType": null,
4364
6110
  "resultType": "PluginPresentationViewsListResult"
4365
6111
  },
6112
+ {
6113
+ "path": "presentation.views.rename",
6114
+ "namespace": "presentation.views",
6115
+ "summary": "Rename a saved view.",
6116
+ "examplePrompts": [
6117
+ "Rename the view Lobby to Entrance Lobby",
6118
+ "Call this view Ground Floor Plan",
6119
+ "Change the active view's name to Final\n\n# Example\n```ts\nconst view = await snaptrude.presentation.views.rename(\"view_123\", \"Entrance\")\n```"
6120
+ ],
6121
+ "argsType": "string",
6122
+ "resultType": "PluginPresentationViewsRenameResult"
6123
+ },
4366
6124
  {
4367
6125
  "path": "presentation.views.setActive",
4368
6126
  "namespace": "presentation.views",
@@ -4376,6 +6134,21 @@
4376
6134
  "argsType": "string",
4377
6135
  "resultType": "PluginPresentationViewsSetActiveResult"
4378
6136
  },
6137
+ {
6138
+ "path": "presentation.views.updateSettings",
6139
+ "namespace": "presentation.views",
6140
+ "summary": "Update a saved view's display settings (partial patch — only the fields you pass change).",
6141
+ "examplePrompts": [
6142
+ "Switch this view to monochrome color mode",
6143
+ "Turn off the axis in the Ground Floor view",
6144
+ "Set the background of the active view to white",
6145
+ "Show area labels on this view",
6146
+ "Enable hidden-line mode for the section view",
6147
+ "Make the 3D view orthographic instead of perspective\n\n# Example\n```ts\nawait snaptrude.presentation.views.updateSettings(\"view_123\", {\ncolorMode: \"monochrome\",\nshowAxis: false,\n})\n// switch a 3D view to an isometric (orthographic) projection\nawait snaptrude.presentation.views.updateSettings(\"view_123\", {\nviewMode: \"isometric\",\n})\n```"
6148
+ ],
6149
+ "argsType": "string",
6150
+ "resultType": "PluginPresentationViewsUpdateSettingsResult"
6151
+ },
4379
6152
  {
4380
6153
  "path": "program.adjacency.compute",
4381
6154
  "namespace": "program.adjacency",
@@ -4409,6 +6182,8 @@
4409
6182
  "examplePrompts": [
4410
6183
  "What's my FAR right now?",
4411
6184
  "Give me the program area summary",
6185
+ "What is my net internal area vs gross external area?",
6186
+ "How much net and gross area do I have?",
4412
6187
  "How much built-up area have I used against the site area?",
4413
6188
  "Am I within my FAR target?\n\n# Example\n```ts\nconst s = await snaptrude.program.areas.get()\nconsole.log(s.builtUp, s.siteArea, s.achievedFar, s.targetFar, s.areaUnit)\n```"
4414
6189
  ],
@@ -4421,6 +6196,7 @@
4421
6196
  "summary": "List the program area rollup grouped by a facet.",
4422
6197
  "examplePrompts": [
4423
6198
  "Break down the area by storey",
6199
+ "Break down net vs gross area by storey",
4424
6200
  "Show the area rollup per department",
4425
6201
  "Group the built-up area by building\n\n# Example\n```ts\nconst { groups } = await snaptrude.program.areas.list(\"storeys\")\nfor (const g of groups) console.log(g.name, g.builtUp, g.count)\n```"
4426
6202
  ],
@@ -4433,12 +6209,25 @@
4433
6209
  "summary": "List the spaces that make up one area group.",
4434
6210
  "examplePrompts": [
4435
6211
  "List the spaces on this storey with their areas",
6212
+ "Which spaces are net and which are gross on this storey?",
4436
6213
  "What rooms are in the Bedrooms department bucket?",
4437
6214
  "Break the storey area down into individual spaces\n\n# Example\n```ts\nconst { members } = await snaptrude.program.areas.listMembers(\"storeys\", \"st_2\")\nfor (const m of members) console.log(m.label, m.carpet)\n```"
4438
6215
  ],
4439
6216
  "argsType": "PluginProgramAreaGroupBy",
4440
6217
  "resultType": "PluginProgramAreasListMembersResult"
4441
6218
  },
6219
+ {
6220
+ "path": "program.areas.refresh",
6221
+ "namespace": "program.areas",
6222
+ "summary": "Force the area breakdown to recompute, then return the fresh summary.",
6223
+ "examplePrompts": [
6224
+ "Recompute the area totals before I read them",
6225
+ "Refresh the FAR numbers",
6226
+ "Make sure the area breakdown is up to date\n\n# Example\n```ts\nconst s = await snaptrude.program.areas.refresh()\nconst { groups } = await snaptrude.program.areas.list(\"storeys\") // now fresh\nconsole.log(s.builtUp, groups.length)\n```"
6227
+ ],
6228
+ "argsType": null,
6229
+ "resultType": "PluginProgramAreasRefreshResult"
6230
+ },
4442
6231
  {
4443
6232
  "path": "program.areas.update",
4444
6233
  "namespace": "program.areas",
@@ -4448,7 +6237,7 @@
4448
6237
  "Override the site area to 5000",
4449
6238
  "Allow a 10 percent FAR deviation\n\n# Example\n```ts\nconst s = await snaptrude.program.areas.update({ targetFar: 2.5 })\nconsole.log(s.achievedFar, s.targetFar)\n```"
4450
6239
  ],
4451
- "argsType": "{ targetFar?: number; siteArea?: number; deviation?: number }",
6240
+ "argsType": "{\n targetFar?: number\n siteArea?: number\n deviation?: number\n }",
4452
6241
  "resultType": "PluginProgramAreasUpdateResult"
4453
6242
  },
4454
6243
  {
@@ -4593,6 +6382,79 @@
4593
6382
  "argsType": "string",
4594
6383
  "resultType": "PluginProgramDepartmentsUpdateResult"
4595
6384
  },
6385
+ {
6386
+ "path": "program.layout.applySolution",
6387
+ "namespace": "program.layout",
6388
+ "summary": "Apply one of the pending arrange solutions.",
6389
+ "examplePrompts": [
6390
+ "Apply the second arrange solution",
6391
+ "Pick layout solution 3 and commit it",
6392
+ "Apply the arrange solution I chose\n\n# Example\n```ts\nawait snaptrude.program.layout.arrange({ autoCommit: false })\nlet job = await snaptrude.program.layout.getState()\nwhile (job?.status === \"running\") {\nawait new Promise((r) => setTimeout(r, 5000))\njob = await snaptrude.program.layout.getState()\n}\nif (job?.status === \"pendingReview\") {\nconsole.log(`${job.totalSolutions} candidate layouts`)\nawait snaptrude.program.layout.applySolution(1) // commit the second one\n}\n```"
6393
+ ],
6394
+ "argsType": "number",
6395
+ "resultType": "PluginProgramLayoutApplyResult"
6396
+ },
6397
+ {
6398
+ "path": "program.layout.arrange",
6399
+ "namespace": "program.layout",
6400
+ "summary": "Arrange the spaces inside the envelope using the computed adjacency data.",
6401
+ "examplePrompts": [
6402
+ "Arrange the rooms in the envelope",
6403
+ "Lay out the departments inside the building envelope",
6404
+ "Auto-arrange the program spaces",
6405
+ "Arrange the rooms but let me pick the solution\n\n# Example\n```ts\nconst { success, error } = await snaptrude.program.layout.arrange()\nif (!success) throw new Error(error)\n// poll until the layout is applied\nlet job = await snaptrude.program.layout.getState()\nwhile (job?.status === \"running\") {\nawait new Promise((r) => setTimeout(r, 5000))\njob = await snaptrude.program.layout.getState()\n}\n```"
6406
+ ],
6407
+ "argsType": "PluginProgramLayoutRunArgs",
6408
+ "resultType": "PluginProgramLayoutRunResult"
6409
+ },
6410
+ {
6411
+ "path": "program.layout.cancel",
6412
+ "namespace": "program.layout",
6413
+ "summary": "Cancel the in-flight layout run.",
6414
+ "examplePrompts": [
6415
+ "Cancel the arrange",
6416
+ "Stop the running layout job",
6417
+ "Abort the pack in envelope\n\n# Example\n```ts\nawait snaptrude.program.layout.cancel()\n```"
6418
+ ],
6419
+ "argsType": null,
6420
+ "resultType": "boolean"
6421
+ },
6422
+ {
6423
+ "path": "program.layout.getState",
6424
+ "namespace": "program.layout",
6425
+ "summary": "Get the state of the layout run.",
6426
+ "examplePrompts": [
6427
+ "Is the arrange done?",
6428
+ "Check the status of the layout run",
6429
+ "Did the pack finish?\n\n# Example\n```ts\nconst job = await snaptrude.program.layout.getState()\nif (job?.status === \"active\") console.log(\"layout applied\")\n```"
6430
+ ],
6431
+ "argsType": null,
6432
+ "resultType": "PluginProgramLayoutStateResult"
6433
+ },
6434
+ {
6435
+ "path": "program.layout.pack",
6436
+ "namespace": "program.layout",
6437
+ "summary": "Pack the spaces into the envelope (a tighter fit than arrange).",
6438
+ "examplePrompts": [
6439
+ "Pack the rooms into the envelope",
6440
+ "Fit the program spaces tightly into the building",
6441
+ "Run pack-in-envelope on this storey\n\n# Example\n```ts\nconst { success } = await snaptrude.program.layout.pack({ envelopeId: \"be_...\" })\nlet job = await snaptrude.program.layout.getState()\nwhile (job?.status === \"running\") {\nawait new Promise((r) => setTimeout(r, 5000))\njob = await snaptrude.program.layout.getState()\n}\n```"
6442
+ ],
6443
+ "argsType": "PluginProgramLayoutRunArgs",
6444
+ "resultType": "PluginProgramLayoutRunResult"
6445
+ },
6446
+ {
6447
+ "path": "program.layout.stack",
6448
+ "namespace": "program.layout",
6449
+ "summary": "Stack the program across **every storey** of the building — the product's *Pack in envelope* / auto-stack.",
6450
+ "examplePrompts": [
6451
+ "Stack the program across all floors",
6452
+ "Auto-stack the departments into the envelope on every storey",
6453
+ "Pack the whole building's program into its envelope\n\n# Example\n```ts\nconst { success, skippedStoreys, error } = await snaptrude.program.layout.stack()\nif (!success) throw new Error(error)\nif (skippedStoreys.length)\nconsole.warn(`No envelope on storeys: ${skippedStoreys.join(\", \")}`)\n```"
6454
+ ],
6455
+ "argsType": null,
6456
+ "resultType": "PluginProgramLayoutStackResult"
6457
+ },
4596
6458
  {
4597
6459
  "path": "program.metrics.get",
4598
6460
  "namespace": "program.metrics",
@@ -4647,6 +6509,30 @@
4647
6509
  "argsType": null,
4648
6510
  "resultType": "PluginProgramSiteContextResult"
4649
6511
  },
6512
+ {
6513
+ "path": "program.site.getLocation",
6514
+ "namespace": "program.site",
6515
+ "summary": "Get the project's geographic location.",
6516
+ "examplePrompts": [
6517
+ "What's the project's latitude and longitude?",
6518
+ "Where is this site located?",
6519
+ "Get the geographic coordinates of the project\n\n# Example\n```ts\nconst location = await snaptrude.program.site.getLocation()\nif (location) console.log(location.latitude, location.longitude)\n```"
6520
+ ],
6521
+ "argsType": null,
6522
+ "resultType": "PluginProgramSiteLocationResult"
6523
+ },
6524
+ {
6525
+ "path": "program.site.getNorthAngle",
6526
+ "namespace": "program.site",
6527
+ "summary": "Get the site's true-north angle.",
6528
+ "examplePrompts": [
6529
+ "What's the north angle of the site?",
6530
+ "How far is the model rotated from true north?",
6531
+ "Get the project's true north direction\n\n# Example\n```ts\nconst northAngle = await snaptrude.program.site.getNorthAngle()\nif (northAngle !== null) console.log(`${northAngle}° from true north`)\n```"
6532
+ ],
6533
+ "argsType": null,
6534
+ "resultType": "PluginProgramSiteNorthAngleResult"
6535
+ },
4650
6536
  {
4651
6537
  "path": "program.site.listGeoPolygons",
4652
6538
  "namespace": "program.site",
@@ -4663,7 +6549,7 @@
4663
6549
  {
4664
6550
  "path": "program.site.listPolygons",
4665
6551
  "namespace": "program.site",
4666
- "summary": "List the site parcels with their footprints (in scene coordinates).",
6552
+ "summary": "List the site parcels with their footprints (world XZ plan coordinates, Snaptrude units).",
4667
6553
  "examplePrompts": [
4668
6554
  "List every site parcel",
4669
6555
  "Show me each plot's footprint",
@@ -4731,7 +6617,7 @@
4731
6617
  "Re-pull all my data bindings",
4732
6618
  "Refresh every binding on the sheets\n\n# Example\n```ts\nawait snaptrude.program.spreadsheet.bindings.refresh({ name: \"takeoff\" })\n```"
4733
6619
  ],
4734
- "argsType": "{ name?: string }",
6620
+ "argsType": "{\n name?: string\n }",
4735
6621
  "resultType": "PluginProgramSpreadsheetBindingsRefreshResult"
4736
6622
  },
4737
6623
  {
@@ -4750,12 +6636,13 @@
4750
6636
  {
4751
6637
  "path": "program.spreadsheet.export",
4752
6638
  "namespace": "program.spreadsheet",
4753
- "summary": "Export the whole report workbook to a file (xlsx, pdf, or csv).",
6639
+ "summary": "Export the report workbook to a file (xlsx, pdf, or csv).",
4754
6640
  "examplePrompts": [
4755
6641
  "Export the report as an Excel file",
4756
6642
  "Download the whole workbook as a PDF",
4757
6643
  "Export the program workbook to xlsx",
4758
- "Save the report as a csv file\n\n# Example\n```ts\nconst file = await snaptrude.program.spreadsheet.export(\"xlsx\")\n// file.fileName, file.mimeType, file.dataBase64\n```"
6644
+ "Save the report as a csv file",
6645
+ "Export the Takeoff sheet as CSV\n\n# Example\n```ts\nconst file = await snaptrude.program.spreadsheet.export(\"xlsx\")\n// file.fileName, file.mimeType, file.dataBase64\n\n// CSV of a specific sheet:\nconst csv = await snaptrude.program.spreadsheet.export(\"csv\", { sheetName: \"Takeoff\" })\n```"
4759
6646
  ],
4760
6647
  "argsType": "PluginSpreadsheetExportFormat",
4761
6648
  "resultType": "PluginProgramSpreadsheetExportResult"
@@ -4770,9 +6657,23 @@
4770
6657
  "Get the last 10 audit log entries",
4771
6658
  "Read the program spreadsheet audit log\n\n# Example\n```ts\nconst { entries } = await snaptrude.program.spreadsheet.getAuditLog({ limit: 10 })\n```"
4772
6659
  ],
4773
- "argsType": "{ limit?: number }",
6660
+ "argsType": "{\n limit?: number\n }",
4774
6661
  "resultType": "PluginProgramSpreadsheetGetAuditLogResult"
4775
6662
  },
6663
+ {
6664
+ "path": "program.spreadsheet.getMaterialTakeoff",
6665
+ "namespace": "program.spreadsheet",
6666
+ "summary": "Read the material take-off dataset (surface area per material, per element type).",
6667
+ "examplePrompts": [
6668
+ "Get the material take-off",
6669
+ "How much of each material is used?",
6670
+ "Read the surface area by material",
6671
+ "Give me the material quantities before I render them",
6672
+ "What's in the material take-off right now?\n\n# Example\n```ts\nconst mto = await snaptrude.program.spreadsheet.getMaterialTakeoff()\nfor (const row of mto.rows) {\nconsole.log(row.objectType, row.family, row.material, row.quantity, row.unit)\n}\n```"
6673
+ ],
6674
+ "argsType": null,
6675
+ "resultType": "PluginProgramSpreadsheetGetMaterialTakeoffResult"
6676
+ },
4776
6677
  {
4777
6678
  "path": "program.spreadsheet.getProgram",
4778
6679
  "namespace": "program.spreadsheet",
@@ -4871,7 +6772,7 @@
4871
6772
  "Recompute all the formulas",
4872
6773
  "Recalculate the Summary sheet\n\n# Example\n```ts\nawait snaptrude.program.spreadsheet.recalculate()\n```"
4873
6774
  ],
4874
- "argsType": "{ sheetName?: string }",
6775
+ "argsType": "{\n sheetName?: string\n }",
4875
6776
  "resultType": "PluginProgramSpreadsheetRecalculateResult"
4876
6777
  },
4877
6778
  {
@@ -4898,7 +6799,7 @@
4898
6799
  "Generate the program schedule sheet titled Program",
4899
6800
  "Render the program filtered to the residential departments\n\n# Example\n```ts\nawait snaptrude.program.spreadsheet.renderProgram({ sheetName: \"Program\" })\n```"
4900
6801
  ],
4901
- "argsType": "{ sheetName?: string; title?: string; filter?: string }",
6802
+ "argsType": "{\n sheetName?: string\n title?: string\n filter?: string\n }",
4902
6803
  "resultType": "PluginProgramSpreadsheetRenderResult"
4903
6804
  },
4904
6805
  {
@@ -4911,7 +6812,7 @@
4911
6812
  "Generate the takeoff schedule sheet titled Takeoff",
4912
6813
  "Render the material takeoff filtered to the walls\n\n# Example\n```ts\nawait snaptrude.program.spreadsheet.renderTakeoff({ sheetName: \"Takeoff\" })\n```"
4913
6814
  ],
4914
- "argsType": "{ sheetName?: string; title?: string; filter?: string }",
6815
+ "argsType": "{\n sheetName?: string\n title?: string\n filter?: string\n }",
4915
6816
  "resultType": "PluginProgramSpreadsheetRenderResult"
4916
6817
  },
4917
6818
  {