@snaptrude/plugin-core 0.8.0 → 0.9.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 (111) hide show
  1. package/CHANGELOG.md +16 -1
  2. package/api-manifest.full.json +1350 -89
  3. package/api-manifest.json +826 -40
  4. package/dist/api/analysis/daylight.d.ts +603 -0
  5. package/dist/api/analysis/daylight.d.ts.map +1 -0
  6. package/dist/api/analysis/heatmaps.d.ts +438 -14
  7. package/dist/api/analysis/heatmaps.d.ts.map +1 -1
  8. package/dist/api/analysis/index.d.ts +15 -0
  9. package/dist/api/analysis/index.d.ts.map +1 -1
  10. package/dist/api/analysis/solar.d.ts +249 -0
  11. package/dist/api/analysis/solar.d.ts.map +1 -0
  12. package/dist/api/analysis/weather.d.ts +193 -0
  13. package/dist/api/analysis/weather.d.ts.map +1 -0
  14. package/dist/api/core/camera/index.d.ts +37 -0
  15. package/dist/api/core/camera/index.d.ts.map +1 -1
  16. package/dist/api/core/geom/create/index.d.ts +318 -1
  17. package/dist/api/core/geom/create/index.d.ts.map +1 -1
  18. package/dist/api/core/index.d.ts +9 -0
  19. package/dist/api/core/index.d.ts.map +1 -1
  20. package/dist/api/core/io/export/index.d.ts +3 -1
  21. package/dist/api/core/io/export/index.d.ts.map +1 -1
  22. package/dist/api/core/io/import/index.d.ts +61 -0
  23. package/dist/api/core/io/import/index.d.ts.map +1 -1
  24. package/dist/api/core/mode/index.d.ts +99 -0
  25. package/dist/api/core/mode/index.d.ts.map +1 -0
  26. package/dist/api/core/storeys/index.d.ts +251 -0
  27. package/dist/api/core/storeys/index.d.ts.map +1 -0
  28. package/dist/api/core/tags.d.ts +24 -0
  29. package/dist/api/core/tags.d.ts.map +1 -1
  30. package/dist/api/core/zoom/index.d.ts +4 -0
  31. package/dist/api/core/zoom/index.d.ts.map +1 -1
  32. package/dist/api/design/create/index.d.ts +115 -4
  33. package/dist/api/design/create/index.d.ts.map +1 -1
  34. package/dist/api/design/delete/index.d.ts +3 -0
  35. package/dist/api/design/delete/index.d.ts.map +1 -1
  36. package/dist/api/design/query/geometry/index.d.ts +112 -0
  37. package/dist/api/design/query/geometry/index.d.ts.map +1 -1
  38. package/dist/api/design/query/index.d.ts +4 -0
  39. package/dist/api/design/query/index.d.ts.map +1 -1
  40. package/dist/api/design/query/referenceLines.d.ts +45 -0
  41. package/dist/api/design/query/referenceLines.d.ts.map +1 -0
  42. package/dist/api/design/query/spaces.d.ts +173 -0
  43. package/dist/api/design/query/spaces.d.ts.map +1 -1
  44. package/dist/api/design/transform/index.d.ts +12 -0
  45. package/dist/api/design/transform/index.d.ts.map +1 -1
  46. package/dist/api/design/update/index.d.ts +51 -1
  47. package/dist/api/design/update/index.d.ts.map +1 -1
  48. package/dist/api/entity/buildableEnvelope.d.ts +4 -0
  49. package/dist/api/entity/buildableEnvelope.d.ts.map +1 -1
  50. package/dist/api/entity/referenceLine.d.ts +8 -0
  51. package/dist/api/entity/referenceLine.d.ts.map +1 -1
  52. package/dist/api/entity/story.d.ts +20 -0
  53. package/dist/api/entity/story.d.ts.map +1 -1
  54. package/dist/api/index.d.ts +5 -0
  55. package/dist/api/index.d.ts.map +1 -1
  56. package/dist/api/presentation/export.d.ts +4 -0
  57. package/dist/api/presentation/export.d.ts.map +1 -1
  58. package/dist/api/presentation/import.d.ts +6 -0
  59. package/dist/api/presentation/import.d.ts.map +1 -1
  60. package/dist/api/presentation/index.d.ts +9 -0
  61. package/dist/api/presentation/index.d.ts.map +1 -1
  62. package/dist/api/presentation/placedViews.d.ts +370 -0
  63. package/dist/api/presentation/placedViews.d.ts.map +1 -0
  64. package/dist/api/presentation/shapes.d.ts +481 -0
  65. package/dist/api/presentation/shapes.d.ts.map +1 -0
  66. package/dist/api/program/site.d.ts +94 -0
  67. package/dist/api/program/site.d.ts.map +1 -1
  68. package/dist/api/program/spreadsheet.d.ts +260 -28
  69. package/dist/api/program/spreadsheet.d.ts.map +1 -1
  70. package/dist/api/workspace/index.d.ts +460 -0
  71. package/dist/api/workspace/index.d.ts.map +1 -0
  72. package/dist/index.cjs +2625 -1758
  73. package/dist/index.cjs.map +1 -1
  74. package/dist/index.js +2515 -1758
  75. package/dist/index.js.map +1 -1
  76. package/package.json +3 -2
  77. package/scripts/generate-manifest.mjs +45 -0
  78. package/src/api/analysis/daylight.ts +470 -0
  79. package/src/api/analysis/heatmaps.ts +444 -17
  80. package/src/api/analysis/index.ts +15 -0
  81. package/src/api/analysis/solar.ts +237 -0
  82. package/src/api/analysis/weather.ts +179 -0
  83. package/src/api/core/camera/index.ts +39 -0
  84. package/src/api/core/geom/create/index.ts +344 -1
  85. package/src/api/core/index.ts +9 -0
  86. package/src/api/core/io/export/index.ts +3 -1
  87. package/src/api/core/io/import/index.ts +64 -0
  88. package/src/api/core/mode/index.ts +96 -0
  89. package/src/api/core/storeys/index.ts +279 -0
  90. package/src/api/core/tags.ts +27 -0
  91. package/src/api/core/zoom/index.ts +4 -0
  92. package/src/api/design/create/index.ts +138 -1
  93. package/src/api/design/delete/index.ts +3 -0
  94. package/src/api/design/query/geometry/index.ts +125 -3
  95. package/src/api/design/query/index.ts +4 -0
  96. package/src/api/design/query/referenceLines.ts +52 -0
  97. package/src/api/design/query/spaces.ts +143 -0
  98. package/src/api/design/transform/index.ts +12 -0
  99. package/src/api/design/update/index.ts +66 -1
  100. package/src/api/entity/buildableEnvelope.ts +4 -0
  101. package/src/api/entity/referenceLine.ts +8 -0
  102. package/src/api/entity/story.ts +20 -0
  103. package/src/api/index.ts +5 -0
  104. package/src/api/presentation/export.ts +4 -0
  105. package/src/api/presentation/import.ts +6 -0
  106. package/src/api/presentation/index.ts +9 -0
  107. package/src/api/presentation/placedViews.ts +363 -0
  108. package/src/api/presentation/shapes.ts +274 -0
  109. package/src/api/program/site.ts +95 -0
  110. package/src/api/program/spreadsheet.ts +251 -6
  111. package/src/api/workspace/index.ts +516 -0
@@ -1,4 +1,30 @@
1
1
  [
2
+ {
3
+ "path": "analysis.daylight.compute",
4
+ "namespace": "analysis.daylight",
5
+ "summary": "Compute annual daylight metrics for the model's spaces.",
6
+ "examplePrompts": [
7
+ "Run an LM-83 ASE daylight analysis on all my spaces",
8
+ "Which rooms fail annual sunlight exposure?",
9
+ "Compute ASE with a 0.6m sensor grid at desk height",
10
+ "Run an LM-83 sDA analysis with blinds operated",
11
+ "Which spaces meet sDA300/50%?",
12
+ "Compute sDA with 70% reflective ceilings and Tvis 0.6 glazing\n\n# Example\n```ts\nlet res = await snaptrude.analysis.daylight.compute({\nstandard: \"IES-LM-83-23\",\nmetrics: [\"sDA\", \"ASE\"],\ngrid: { spacingM: 0.6, workplaneHeightM: 0.76, boundaryOffsetM: 0.5 },\noptics: { materials: { \"Glass - Clear\": { transmittance: 0.6 } } },\n})\nconst runId = res.runId\nwhile (res.status === \"running\" && runId) {\nawait new Promise((r) => setTimeout(r, 5000))\nres = await snaptrude.analysis.daylight.poll({ runId })\n}\nconst failing = res.aggregates.filter(\n(a) => a.scope === \"space\" && (a.sdaPercent ?? 0) < 55,\n)\n```"
13
+ ],
14
+ "argsType": "PluginDaylightComputeArgs",
15
+ "resultType": "PluginDaylightResults"
16
+ },
17
+ {
18
+ "path": "analysis.daylight.poll",
19
+ "namespace": "analysis.daylight",
20
+ "summary": "Poll an asynchronous daylight run started by {@linkcode PluginAnalysisDaylightApi.compute}.",
21
+ "examplePrompts": [
22
+ "Check whether my sDA run has finished",
23
+ "Get the results of the daylight run"
24
+ ],
25
+ "argsType": "PluginDaylightPollArgs",
26
+ "resultType": "PluginDaylightResults"
27
+ },
2
28
  {
3
29
  "path": "analysis.heatmaps.isActive",
4
30
  "namespace": "analysis.heatmaps",
@@ -11,6 +37,79 @@
11
37
  "argsType": null,
12
38
  "resultType": "boolean"
13
39
  },
40
+ {
41
+ "path": "analysis.heatmaps.overlays.hide",
42
+ "namespace": "analysis.heatmaps.overlays",
43
+ "summary": "Hide an overlay without removing it.",
44
+ "examplePrompts": [
45
+ "Hide the wind overlay but keep it around",
46
+ "Temporarily hide my heatmap",
47
+ "Turn off the occupancy colours without deleting them\n\n# Example\n```ts\nawait snaptrude.analysis.heatmaps.overlays.hide(\"wind\")\n```"
48
+ ],
49
+ "argsType": "string",
50
+ "resultType": "boolean"
51
+ },
52
+ {
53
+ "path": "analysis.heatmaps.overlays.list",
54
+ "namespace": "analysis.heatmaps.overlays",
55
+ "summary": "List the registered heatmap overlays.",
56
+ "examplePrompts": [
57
+ "Which heatmap overlays do I have?",
58
+ "List my rendered analysis overlays",
59
+ "Check which heatmap is currently visible\n\n# Example\n```ts\nconst { overlays } = await snaptrude.analysis.heatmaps.overlays.list()\nconst visible = overlays.find((o) => o.visible)\n```"
60
+ ],
61
+ "argsType": null,
62
+ "resultType": "PluginAnalysisHeatmapOverlaysListResult"
63
+ },
64
+ {
65
+ "path": "analysis.heatmaps.overlays.remove",
66
+ "namespace": "analysis.heatmaps.overlays",
67
+ "summary": "Remove an overlay — dispose its meshes and forget it.",
68
+ "examplePrompts": [
69
+ "Delete the wind overlay",
70
+ "Remove my occupancy heatmap for good",
71
+ "Free up an overlay slot\n\n# Example\n```ts\nawait snaptrude.analysis.heatmaps.overlays.remove(\"wind\")\n```"
72
+ ],
73
+ "argsType": "string",
74
+ "resultType": "boolean"
75
+ },
76
+ {
77
+ "path": "analysis.heatmaps.overlays.removeAll",
78
+ "namespace": "analysis.heatmaps.overlays",
79
+ "summary": "Remove every registered overlay and close the legend.",
80
+ "examplePrompts": [
81
+ "Clear all my heatmap overlays",
82
+ "Remove every analysis overlay from the scene",
83
+ "Start over with a clean set of overlays\n\n# Example\n```ts\nconst removed = await snaptrude.analysis.heatmaps.overlays.removeAll()\n```"
84
+ ],
85
+ "argsType": null,
86
+ "resultType": "number"
87
+ },
88
+ {
89
+ "path": "analysis.heatmaps.overlays.show",
90
+ "namespace": "analysis.heatmaps.overlays",
91
+ "summary": "Make a registered overlay the visible one.",
92
+ "examplePrompts": [
93
+ "Switch back to my wind heatmap",
94
+ "Show the occupancy overlay",
95
+ "Flip between my two analysis overlays\n\n# Example\n```ts\nawait snaptrude.analysis.heatmaps.overlays.show(\"wind\")\n```"
96
+ ],
97
+ "argsType": "string",
98
+ "resultType": "boolean"
99
+ },
100
+ {
101
+ "path": "analysis.heatmaps.renderField",
102
+ "namespace": "analysis.heatmaps",
103
+ "summary": "Render a heatmap from **arbitrary cell geometry** — planar polygons or pre-tessellated meshes, one scalar value each.",
104
+ "examplePrompts": [
105
+ "Overlay my FEA stress results on their solver mesh",
106
+ "Color these Voronoi regions by footfall",
107
+ "Paint each façade panel polygon by its PV yield",
108
+ "Render pass/fail daylight compliance per zone polygon\n\n# Example\n```ts\n// Two triangular cells at ground level, coloured pass/fail at 300 lux.\nawait snaptrude.analysis.heatmaps.renderField(\n[\n{ polygon: [{ x: 0, y: 0, z: 0 }, { x: 4, y: 0, z: 0 }, { x: 0, y: 0, z: 4 }], value: 420 },\n{ polygon: [{ x: 4, y: 0, z: 4 }, { x: 0, y: 0, z: 4 }, { x: 4, y: 0, z: 0 }], value: 180 },\n],\n{ title: \"Daylight\", unit: \"lux\", scale: { type: \"threshold\", threshold: 300 } },\n)\n```"
109
+ ],
110
+ "argsType": "PluginAnalysisHeatmapFieldCell[]",
111
+ "resultType": "PluginAnalysisHeatmapsRenderResult"
112
+ },
14
113
  {
15
114
  "path": "analysis.heatmaps.renderGrid",
16
115
  "namespace": "analysis.heatmaps",
@@ -35,10 +134,23 @@
35
134
  "argsType": "PluginAnalysisHeatmapSpaceEntry[]",
36
135
  "resultType": "PluginAnalysisHeatmapsRenderResult"
37
136
  },
137
+ {
138
+ "path": "analysis.heatmaps.renderSurfaceGrid",
139
+ "namespace": "analysis.heatmaps",
140
+ "summary": "Render a grid heatmap on an **arbitrarily oriented plane** — a façade, a section cut, any flat surface.",
141
+ "examplePrompts": [
142
+ "Paint the solar irradiance results on the south façade",
143
+ "Show my daylight values as a heatmap on this wall",
144
+ "Render panel-level PV yield on the building face",
145
+ "Overlay wind pressure on the tower's west elevation\n\n# Example\n```ts\n// Samples lie on a wall plane facing +X; colour each 1-unit cell by irradiance.\nawait snaptrude.analysis.heatmaps.renderSurfaceGrid(\nsamples.map((s) => ({ position: { x: wallX, y: s.y, z: s.z }, value: s.irradiance })),\n1,\n{ x: 1, y: 0, z: 0 }, // façade normal\n{ title: \"Irradiance\", unit: \"kWh/m²\", colors: [\"#0000ff\", \"#ffff00\", \"#ff0000\"] },\n)\n```"
146
+ ],
147
+ "argsType": "PluginAnalysisHeatmapGridCell[]",
148
+ "resultType": "PluginAnalysisHeatmapsRenderResult"
149
+ },
38
150
  {
39
151
  "path": "analysis.heatmaps.reset",
40
152
  "namespace": "analysis.heatmaps",
41
- "summary": "Clear the plugin heatmap from the scene.",
153
+ "summary": "Clear every plugin heatmap overlay from the scene.",
42
154
  "examplePrompts": [
43
155
  "Clear my custom heatmap",
44
156
  "Remove the wind overlay from the model",
@@ -155,6 +267,18 @@
155
267
  "argsType": "string",
156
268
  "resultType": "PluginAnalysisShadowsDateTimeResult"
157
269
  },
270
+ {
271
+ "path": "analysis.solar.sampleGrid",
272
+ "namespace": "analysis.solar",
273
+ "summary": "Sample solar exposure at a set of points.",
274
+ "examplePrompts": [
275
+ "What's the irradiance at these facade points at noon on June 21?",
276
+ "How shaded are these balcony points across the summer?",
277
+ "Sample direct sun visibility at these roof points right now\n\n# Example\n```ts\nconst grid = await snaptrude.analysis.solar.sampleGrid({\npoints: [\n{ id: \"a\", position: [0, 3, 0] },\n{ id: \"b\", position: [5, 3, 0], normal: [0, 0, 1] },\n],\ndateTime: \"2026-06-21T12:00:00+05:30\",\n})\nfor (const r of grid.results) {\nconsole.log(r.id, r.directSunVisible, r.totalIrradiance, grid.units)\n}\n```"
278
+ ],
279
+ "argsType": "PluginSolarSampleGridArgs",
280
+ "resultType": "PluginSolarSampleGridResult"
281
+ },
158
282
  {
159
283
  "path": "analysis.sunlightHours.cancel",
160
284
  "namespace": "analysis.sunlightHours",
@@ -239,6 +363,18 @@
239
363
  "argsType": null,
240
364
  "resultType": "boolean"
241
365
  },
366
+ {
367
+ "path": "analysis.weather.getSeries",
368
+ "namespace": "analysis.weather",
369
+ "summary": "Get the hourly weather series for a date range, paged.",
370
+ "examplePrompts": [
371
+ "Get the weather series for June at my site",
372
+ "Pull the hourly temperature and irradiance for this location",
373
+ "What EPW weather file is my project using?\n\n# Example\n```ts\nlet cursor: string | undefined = undefined\nconst rows = []\ndo {\nconst page = await snaptrude.analysis.weather.getSeries({\nstartDate: \"2026-06-01\",\nendDate: \"2026-06-30\",\ncursor,\n})\nrows.push(...page.rows)\ncursor = page.nextCursor ?? undefined\n} while (cursor)\n```"
374
+ ],
375
+ "argsType": "PluginWeatherGetSeriesArgs",
376
+ "resultType": "PluginWeatherSeriesResult"
377
+ },
242
378
  {
243
379
  "path": "core.buildings.copy",
244
380
  "namespace": "core.buildings",
@@ -347,6 +483,18 @@
347
483
  "argsType": "string",
348
484
  "resultType": "PluginCoreBuildingsUpdateResult"
349
485
  },
486
+ {
487
+ "path": "core.camera.getProjection",
488
+ "namespace": "core.camera",
489
+ "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.",
490
+ "examplePrompts": [
491
+ "Is the camera in perspective or orthographic?",
492
+ "What projection is the 3D view using?",
493
+ "Check whether perspective is on\n\n# Example\n```ts\nconst projection = await snaptrude.core.camera.getProjection()\nconsole.log(projection) // \"perspective\" | \"orthographic\"\n```"
494
+ ],
495
+ "argsType": null,
496
+ "resultType": "PluginCameraProjection"
497
+ },
350
498
  {
351
499
  "path": "core.camera.lookFrom",
352
500
  "namespace": "core.camera",
@@ -373,6 +521,19 @@
373
521
  "argsType": "PluginCameraMode",
374
522
  "resultType": "boolean"
375
523
  },
524
+ {
525
+ "path": "core.camera.setProjection",
526
+ "namespace": "core.camera",
527
+ "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.",
528
+ "examplePrompts": [
529
+ "Switch the camera to orthographic",
530
+ "Turn perspective off",
531
+ "Give me a perspective view of the model",
532
+ "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```"
533
+ ],
534
+ "argsType": "PluginCameraProjection",
535
+ "resultType": "boolean"
536
+ },
376
537
  {
377
538
  "path": "core.camera.setStandardView",
378
539
  "namespace": "core.camera",
@@ -387,6 +548,32 @@
387
548
  "argsType": "PluginStandardView",
388
549
  "resultType": "boolean"
389
550
  },
551
+ {
552
+ "path": "core.camera.zoomExtents",
553
+ "namespace": "core.camera",
554
+ "summary": "Zoom (fit) the camera to all geometry in the scene — the \"zoom extents\" action. View-state only — not undoable. Canonical home of the zoom-extents read (the deprecated `core.zoom.extents`).",
555
+ "examplePrompts": [
556
+ "Zoom out so I can see the whole model",
557
+ "Fit everything in the view",
558
+ "Frame the entire building in the viewport",
559
+ "Do a zoom extents on the canvas\n\n# Example\n```ts\nawait snaptrude.core.camera.zoomExtents()\n```"
560
+ ],
561
+ "argsType": null,
562
+ "resultType": "boolean"
563
+ },
564
+ {
565
+ "path": "core.camera.zoomSelection",
566
+ "namespace": "core.camera",
567
+ "summary": "Zoom (fit) the camera to the current selection. View-state only — not undoable. Canonical home of the zoom-to-selection read (the deprecated `core.zoom.selection`).",
568
+ "examplePrompts": [
569
+ "Zoom in on what I have selected",
570
+ "Frame the selected walls in the view",
571
+ "Focus the camera on my current selection",
572
+ "Fit the view to the selected room\n\n# Example\n```ts\nawait snaptrude.core.camera.zoomSelection()\n```"
573
+ ],
574
+ "argsType": null,
575
+ "resultType": "boolean"
576
+ },
390
577
  {
391
578
  "path": "core.comment.create",
392
579
  "namespace": "core.comment",
@@ -413,6 +600,19 @@
413
600
  "argsType": "CommentHandle",
414
601
  "resultType": "boolean"
415
602
  },
603
+ {
604
+ "path": "core.comment.get",
605
+ "namespace": "core.comment",
606
+ "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.",
607
+ "examplePrompts": [
608
+ "Read the comment on this wall and tell me what it says",
609
+ "Who left this comment and where is it pinned?",
610
+ "Show me the full thread for this comment",
611
+ "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```"
612
+ ],
613
+ "argsType": "CommentHandle",
614
+ "resultType": "PluginCommentDetails | null"
615
+ },
416
616
  {
417
617
  "path": "core.comment.isResolved",
418
618
  "namespace": "core.comment",
@@ -452,6 +652,19 @@
452
652
  "argsType": "CommentHandle",
453
653
  "resultType": "boolean"
454
654
  },
655
+ {
656
+ "path": "core.comment.reply",
657
+ "namespace": "core.comment",
658
+ "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.",
659
+ "examplePrompts": [
660
+ "Reply to this comment saying I fixed the wall height",
661
+ "Add a reply to the review note confirming it's done",
662
+ "Respond to the comment about the door with \"looks good now\"",
663
+ "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```"
664
+ ],
665
+ "argsType": "CommentHandle",
666
+ "resultType": "CommentHandle"
667
+ },
455
668
  {
456
669
  "path": "core.comment.resolve",
457
670
  "namespace": "core.comment",
@@ -502,6 +715,90 @@
502
715
  "argsType": "Vec3Handle",
503
716
  "resultType": "ArcHandle"
504
717
  },
718
+ {
719
+ "path": "core.geom.create.brepFromExtrusion",
720
+ "namespace": "core.geom.create",
721
+ "summary": "Create a closed solid **B-rep** by extruding a contour along a direction. Host API call — returns a {@linkcode BrepHandle}. The direction is normalised by the host, so `amount` is the extrusion distance in raw Babylon units (negative extrudes the opposite way). The contour is copied — the input handle is never mutated. Holes and arc/circle profiles extrude natively (a circle profile yields a cylinder).",
722
+ "examplePrompts": [
723
+ "Extrude this profile 3 metres up",
724
+ "Make a solid by extruding this outline",
725
+ "Create a cylinder from a circle profile\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 brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)\nconst faceCount = await snaptrude.core.geom.query.brep.getFaceCount(brep) // 6\n```"
726
+ ],
727
+ "argsType": "ContourHandle",
728
+ "resultType": "BrepHandle"
729
+ },
730
+ {
731
+ "path": "core.geom.create.brepFromFaces",
732
+ "namespace": "core.geom.create",
733
+ "summary": "Create a closed solid **B-rep** from explicit face loops. Host API call — returns a {@linkcode BrepHandle}. Faces are plain arrays of `{x, y, z}` point components, NOT point handles (bulk-data precedent: `design.query.geometry.getTriangulatedMeshes`), in raw Babylon units.",
734
+ "examplePrompts": [
735
+ "Create a brep from faces",
736
+ "Build a custom solid from a set of faces",
737
+ "Make a pyramid from triangular faces\n\n# Example\n```ts\n// A pyramid: square base + 4 triangular sides\nconst apex = { x: 0, y: 4, z: 0 }\nconst a = { x: -2, y: 0, z: -2 }\nconst b = { x: 2, y: 0, z: -2 }\nconst c = { x: 2, y: 0, z: 2 }\nconst d = { x: -2, y: 0, z: 2 }\nconst brep = await snaptrude.core.geom.create.brepFromFaces([\n[a, d, c, b], // base\n[a, b, apex],\n[b, c, apex],\n[c, d, apex],\n[d, a, apex],\n])\nconst faceCount = await snaptrude.core.geom.query.brep.getFaceCount(brep) // 5\n```"
738
+ ],
739
+ "argsType": "Vec3Components[][]",
740
+ "resultType": "BrepHandle"
741
+ },
742
+ {
743
+ "path": "core.geom.create.brepFromIntersection",
744
+ "namespace": "core.geom.create",
745
+ "summary": "Create a closed solid **B-rep** as the boolean **intersection** of two breps (`a ∩ b` — the shared volume only). Host API call — returns a new {@linkcode BrepHandle}. Inputs are read-only and may be authored or scene-derived breps (see {@linkcode PluginGeomCreateApi.brepFromUnion}); coordinates are combined as-is.",
746
+ "examplePrompts": [
747
+ "Keep only the overlap of these two solids",
748
+ "Intersect these two masses",
749
+ "Clip the tower to the zoning envelope\n\n# Example\n```ts\nconst overlap = await snaptrude.core.geom.create.brepFromIntersection(towerBrep, envelopeBrep)\n```"
750
+ ],
751
+ "argsType": "BrepHandle",
752
+ "resultType": "BrepHandle"
753
+ },
754
+ {
755
+ "path": "core.geom.create.brepFromLoft",
756
+ "namespace": "core.geom.create",
757
+ "summary": "Create a closed solid **B-rep** by lofting between a bottom and a top contour. Host API call — returns a {@linkcode BrepHandle}. Both contours must have the same number of edges (and matching hole counts); side faces connect corresponding edges by authored index. Corresponding edges must stay coplanar — a twisted loft would produce non-planar side faces and is rejected. The contours are copied — the input handles are never mutated.",
758
+ "examplePrompts": [
759
+ "Make a tapered tower from these two outlines",
760
+ "Loft between a large base and a smaller top",
761
+ "Create a frustum from two squares\n\n# Example\n```ts\n// A square frustum: 4m base lofted to a 2m top, 3m up\nconst base = await snaptrude.core.geom.create.profileRect(4, 4)\nconst top = await snaptrude.core.geom.create.profileRect(2, 2, await snaptrude.core.math.vec3.new(0, 3, 0))\nconst brep = await snaptrude.core.geom.create.brepFromLoft(\nawait snaptrude.core.geom.create.contourFromProfile(base),\nawait snaptrude.core.geom.create.contourFromProfile(top),\n)\nconst faceCount = await snaptrude.core.geom.query.brep.getFaceCount(brep) // 6\n```"
762
+ ],
763
+ "argsType": "ContourHandle",
764
+ "resultType": "BrepHandle"
765
+ },
766
+ {
767
+ "path": "core.geom.create.brepFromMesh",
768
+ "namespace": "core.geom.create",
769
+ "summary": "Create a closed solid **B-rep** from indexed mesh data: a vertex position array plus face loops of indices into it. Host API call — returns a {@linkcode BrepHandle}. The indexed form of {@linkcode PluginGeomCreateApi.brepFromFaces} — same validation (planar faces, closed manifold solid, every edge shared by exactly two faces) after the indices are expanded to point loops.",
770
+ "examplePrompts": [
771
+ "Create a brep from mesh vertices and indices",
772
+ "Turn this indexed mesh into a solid",
773
+ "Build a solid from vertex positions and face indices\n\n# Example\n```ts\n// A tetrahedron from 4 vertices and 4 triangular faces\nconst positions = [\n{ x: 0, y: 0, z: 0 },\n{ x: 4, y: 0, z: 0 },\n{ x: 2, y: 0, z: 4 },\n{ x: 2, y: 3, z: 1.5 },\n]\nconst brep = await snaptrude.core.geom.create.brepFromMesh(positions, [\n[0, 2, 1], // base\n[0, 1, 3],\n[1, 2, 3],\n[2, 0, 3],\n])\nconst vertexCount = await snaptrude.core.geom.query.brep.getVertexCount(brep) // 4\n```"
774
+ ],
775
+ "argsType": "Vec3Components[]",
776
+ "resultType": "BrepHandle"
777
+ },
778
+ {
779
+ "path": "core.geom.create.brepFromSubtraction",
780
+ "namespace": "core.geom.create",
781
+ "summary": "Create a closed solid **B-rep** as the boolean **subtraction** of two breps: **`a` minus `b`** — `b` is cut away from `a`. Host API call — returns a new {@linkcode BrepHandle}. Argument order matters: `brepFromSubtraction(a, b)` removes `b`'s volume from `a`. Inputs are read-only and may be authored or scene-derived breps (see {@linkcode PluginGeomCreateApi.brepFromUnion}); coordinates are combined as-is.",
782
+ "examplePrompts": [
783
+ "Subtract the courtyard from the building mass",
784
+ "Cut this solid out of that one",
785
+ "Punch a hole through the slab with this box\n\n# Example\n```ts\n// buildingBrep minus courtyardBrep — order matters\nconst carved = await snaptrude.core.geom.create.brepFromSubtraction(buildingBrep, courtyardBrep)\n```"
786
+ ],
787
+ "argsType": "BrepHandle",
788
+ "resultType": "BrepHandle"
789
+ },
790
+ {
791
+ "path": "core.geom.create.brepFromUnion",
792
+ "namespace": "core.geom.create",
793
+ "summary": "Create a closed solid **B-rep** as the boolean **union** of two breps (`a ∪ b`). Host API call — returns a new {@linkcode BrepHandle}. Inputs are read-only and may be authored breps (any `core.geom.create` brep constructor) or scene-derived breps from `design.query.geometry.getBrep`; coordinates are combined as-is, so both inputs must share a frame. The result must be a single solid — disjoint inputs are rejected.",
794
+ "examplePrompts": [
795
+ "Union these two solids",
796
+ "Merge these breps into one mass",
797
+ "Combine the tower and the podium into a single solid\n\n# Example\n```ts\nconst a = await snaptrude.core.geom.create.brepFromExtrusion(baseContour, { x: 0, y: 1, z: 0 }, 3)\nconst b = await snaptrude.core.geom.create.brepFromExtrusion(overlappingContour, { x: 0, y: 1, z: 0 }, 5)\nconst merged = await snaptrude.core.geom.create.brepFromUnion(a, b)\n```"
798
+ ],
799
+ "argsType": "BrepHandle",
800
+ "resultType": "BrepHandle"
801
+ },
505
802
  {
506
803
  "path": "core.geom.create.circle",
507
804
  "namespace": "core.geom.create",
@@ -581,7 +878,8 @@
581
878
  "summary": "Free a transient contour resource handle — releases its registry entry and reclaims its share of the plugin's resource quota. Handle-lifecycle only; does NOT tear down engine-side geometry, nor the contour's child profile handles.",
582
879
  "examplePrompts": [],
583
880
  "argsType": "ContourHandle",
584
- "resultType": "void"
881
+ "resultType": "void",
882
+ "deprecated": "core.handles.release"
585
883
  },
586
884
  {
587
885
  "path": "core.geom.delete.profile",
@@ -589,7 +887,8 @@
589
887
  "summary": "Free a transient profile resource handle — releases its registry entry and reclaims its share of the plugin's resource quota. This is a handle-lifecycle operation only and does NOT tear down any engine-side geometry.",
590
888
  "examplePrompts": [],
591
889
  "argsType": "ProfileHandle",
592
- "resultType": "void"
890
+ "resultType": "void",
891
+ "deprecated": "core.handles.release"
593
892
  },
594
893
  {
595
894
  "path": "core.geom.query.arc.getAxis",
@@ -2138,7 +2437,8 @@
2138
2437
  "Export the model as a GLB",
2139
2438
  "Give me the whole scene as an OBJ file",
2140
2439
  "Export just my selection to GLB",
2141
- "Download the model as a glTF binary\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```"
2440
+ "Download the model as an FBX file",
2441
+ "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```"
2142
2442
  ],
2143
2443
  "argsType": "ExportModelFormat",
2144
2444
  "resultType": "ExportedFile"
@@ -2168,6 +2468,18 @@
2168
2468
  "argsType": "string",
2169
2469
  "resultType": "ImportJobHandle"
2170
2470
  },
2471
+ {
2472
+ "path": "core.io.import.epw",
2473
+ "namespace": "core.io.import",
2474
+ "summary": "Import an **EPW weather file** into the project's weather catalog.",
2475
+ "examplePrompts": [
2476
+ "Import this EPW weather file for the site",
2477
+ "Upload a custom weather file for the daylight analysis",
2478
+ "Use this .epw as the project's weather source\n\n# Example\n```ts\nconst { weatherFileId, label } = await snaptrude.core.io.import.epw(\n\"https://example.com/Chicago-OHare.epw\",\n)\nconsole.log(`Weather set to ${label} (${weatherFileId})`)\n```"
2479
+ ],
2480
+ "argsType": "string",
2481
+ "resultType": "PluginImportEpwResult"
2482
+ },
2171
2483
  {
2172
2484
  "path": "core.io.import.image",
2173
2485
  "namespace": "core.io.import",
@@ -2871,6 +3183,41 @@
2871
3183
  "argsType": "Vec3Handle",
2872
3184
  "resultType": "Vec3Handle"
2873
3185
  },
3186
+ {
3187
+ "path": "core.mode.get",
3188
+ "namespace": "core.mode",
3189
+ "summary": "Get the currently active application mode.",
3190
+ "examplePrompts": [
3191
+ "Which mode am I in right now?",
3192
+ "Am I in present mode?",
3193
+ "Check whether the editor is in BIM mode\n\n# Example\n```ts\nconst mode = await snaptrude.core.mode.get()\nif (mode !== \"present\") await snaptrude.core.mode.set(\"present\")\n```"
3194
+ ],
3195
+ "argsType": null,
3196
+ "resultType": "PluginAppMode"
3197
+ },
3198
+ {
3199
+ "path": "core.mode.list",
3200
+ "namespace": "core.mode",
3201
+ "summary": "List every application mode the editor has.",
3202
+ "examplePrompts": [
3203
+ "What modes does Snaptrude have?",
3204
+ "List the editor modes I can switch to\n\n# Example\n```ts\nconst { modes } = await snaptrude.core.mode.list()\n// [\"design\", \"bim\", \"present\", \"program\"]\n```"
3205
+ ],
3206
+ "argsType": null,
3207
+ "resultType": "PluginCoreModeListResult"
3208
+ },
3209
+ {
3210
+ "path": "core.mode.set",
3211
+ "namespace": "core.mode",
3212
+ "summary": "Switch the editor to another application mode — the same action as clicking that tab in the top menu bar.",
3213
+ "examplePrompts": [
3214
+ "Switch to present mode",
3215
+ "Open BIM mode",
3216
+ "Go back to design mode\n\n# Example\n```ts\nawait snaptrude.core.mode.set(\"present\")\n// ... presentation work ...\nawait snaptrude.core.mode.set(\"design\")\n```"
3217
+ ],
3218
+ "argsType": "PluginAppMode",
3219
+ "resultType": "PluginCoreModeSetResult"
3220
+ },
2874
3221
  {
2875
3222
  "path": "core.project.settings.getTolerance",
2876
3223
  "namespace": "core.project.settings",
@@ -3134,11 +3481,12 @@
3134
3481
  {
3135
3482
  "path": "core.proposals.create",
3136
3483
  "namespace": "core.proposals",
3137
- "summary": "Create a new design option (proposal).",
3484
+ "summary": "Create a new design option (proposal) — blank, or configured from a base proposal (the New Proposal modal's two paths).",
3138
3485
  "examplePrompts": [
3139
3486
  "Create a design option called Scheme B",
3140
3487
  "Add a new proposal named Option 2",
3141
- "Make a fresh design variant to explore\n\n# Example\n```ts\nconst { id } = await snaptrude.core.proposals.create(\"Scheme B\")\n```"
3488
+ "Duplicate the current proposal as Scheme C",
3489
+ "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```"
3142
3490
  ],
3143
3491
  "argsType": "string",
3144
3492
  "resultType": "PluginCoreProposalsCreateResult"
@@ -3239,6 +3587,98 @@
3239
3587
  "argsType": "string",
3240
3588
  "resultType": "PluginCoreProposalsSetActiveResult"
3241
3589
  },
3590
+ {
3591
+ "path": "core.storeys.copy",
3592
+ "namespace": "core.storeys",
3593
+ "summary": "Copy a storey into the adjacent level, up or down.",
3594
+ "examplePrompts": [
3595
+ "Copy this floor to the storey above",
3596
+ "Copy the ground floor down into a new basement",
3597
+ "Repeat this level upwards with its own independent geometry",
3598
+ "Copy just the selected walls onto the next floor up\n\n# Example\n```ts\n// Copy the whole active storey one level up (instanced copies).\nconst { targetStories, created, skipped } =\nawait snaptrude.core.storeys.copy(\"up\")\nconsole.log(`Copied ${created.length} elements onto storey ${targetStories}`)\nif (skipped) console.log(`${skipped} elements were skipped`)\n```"
3599
+ ],
3600
+ "argsType": "\"up\" | \"down\"",
3601
+ "resultType": "PluginStoryDuplicateResult"
3602
+ },
3603
+ {
3604
+ "path": "core.storeys.create",
3605
+ "namespace": "core.storeys",
3606
+ "summary": "Create a new storey (floor) in the project.",
3607
+ "examplePrompts": [
3608
+ "Add a third floor to the building",
3609
+ "Create a new storey above the second floor",
3610
+ "Add a basement level to this project",
3611
+ "Insert a new level with a custom floor height\n\n# Example\n```ts\n// Create a new third floor with custom height\nconst { storyId } = await snaptrude.core.storeys.create(3, 4.5)\n```"
3612
+ ],
3613
+ "argsType": "number",
3614
+ "resultType": "PluginStoryCreateResult"
3615
+ },
3616
+ {
3617
+ "path": "core.storeys.delete",
3618
+ "namespace": "core.storeys",
3619
+ "summary": "Delete a storey and everything on it — the same as removing it from the storey panel. Every element placed on the storey (walls, floors, masses, …) is deleted with it, the remaining storeys are re-stacked, and the active storey falls back to an adjacent one. Committed as a single undo step.",
3620
+ "examplePrompts": [
3621
+ "Delete the top floor",
3622
+ "Remove the basement level",
3623
+ "Get rid of storey 3",
3624
+ "Delete the second floor and everything on it\n\n# Example\n```ts\nconst { newActiveStory } = await snaptrude.core.storeys.delete(3)\nconsole.log(`Deleted storey 3; now on storey ${newActiveStory}`)\n```"
3625
+ ],
3626
+ "argsType": "number",
3627
+ "resultType": "PluginStoryDeleteResult"
3628
+ },
3629
+ {
3630
+ "path": "core.storeys.get",
3631
+ "namespace": "core.storeys",
3632
+ "summary": "Get properties of a storey by its storey number.",
3633
+ "examplePrompts": [
3634
+ "What is the height of the ground floor?",
3635
+ "How many rooms are on the second storey?",
3636
+ "Get the total floor area of level 3",
3637
+ "Is the first floor hidden in the viewport?",
3638
+ "Show me the name and height of storey 2\n\n# Example\n```ts\nconst info = await snaptrude.core.storeys.get(1, [\"height\", \"name\", \"spacesCount\"])\nconsole.log(info.name, info.height, info.spacesCount)\n```"
3639
+ ],
3640
+ "argsType": "number",
3641
+ "resultType": "PluginStoryGetResult"
3642
+ },
3643
+ {
3644
+ "path": "core.storeys.list",
3645
+ "namespace": "core.storeys",
3646
+ "summary": "List all storeys in the current project.",
3647
+ "examplePrompts": [
3648
+ "How many floors does this building have?",
3649
+ "List all the storeys in the project",
3650
+ "Show me every level with its name",
3651
+ "Which storeys exist in this model?\n\n# Example\n```ts\nconst { storeys } = await snaptrude.core.storeys.list()\nfor (const s of storeys) {\nconsole.log(`Storey ${s.value}: ${s.name} (id: ${s.id})`)\n}\n```"
3652
+ ],
3653
+ "argsType": null,
3654
+ "resultType": "PluginCoreStoreysListResult"
3655
+ },
3656
+ {
3657
+ "path": "core.storeys.setActive",
3658
+ "namespace": "core.storeys",
3659
+ "summary": "Make a storey the active storey — the same as clicking it in the storey/layer panel. Subsequent draws and creates target this storey, and in 2D the viewport switches to it. This is a view/navigation change: it is **not** undoable and commits nothing to the model.",
3660
+ "examplePrompts": [
3661
+ "Switch to the second floor",
3662
+ "Make the ground storey active",
3663
+ "Go to the basement level",
3664
+ "Set level 3 as the current storey\n\n# Example\n```ts\n// Activate storey 2, then draw a wall — it lands on storey 2.\nawait snaptrude.core.storeys.setActive(2)\n```"
3665
+ ],
3666
+ "argsType": "number",
3667
+ "resultType": "PluginStorySetActiveResult"
3668
+ },
3669
+ {
3670
+ "path": "core.storeys.update",
3671
+ "namespace": "core.storeys",
3672
+ "summary": "Update a storey's floor-to-floor `height` and/or `name`.",
3673
+ "examplePrompts": [
3674
+ "Change the ground floor height to 3.5 metres",
3675
+ "Make the second storey taller",
3676
+ "Rename the ground floor to \"Lobby\"",
3677
+ "Set the floor-to-floor height of level 1\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.core.storeys.update(1, 5)\n// Rename only, leaving the height untouched.\nawait snaptrude.core.storeys.update(1, undefined, { name: \"Lobby\" })\n```"
3678
+ ],
3679
+ "argsType": "number",
3680
+ "resultType": "PluginStoryUpdateResult"
3681
+ },
3242
3682
  {
3243
3683
  "path": "core.tags.assign",
3244
3684
  "namespace": "core.tags",
@@ -3333,7 +3773,8 @@
3333
3773
  "Show the labels applied to this room\n\n# Example\n```ts\nconst { tags } = await snaptrude.core.tags.getTagsForComponent(\"cmp_42\")\nfor (const t of tags) console.log(t.categoryName, t.tagName)\n```"
3334
3774
  ],
3335
3775
  "argsType": "ComponentHandle",
3336
- "resultType": "PluginCoreTagsGetTagsForComponentResult"
3776
+ "resultType": "PluginCoreTagsGetTagsForComponentResult",
3777
+ "deprecated": "core.tags.listForComponent"
3337
3778
  },
3338
3779
  {
3339
3780
  "path": "core.tags.list",
@@ -3371,6 +3812,18 @@
3371
3812
  "argsType": "{ tagId?: string; categoryId?: string; untagged?: boolean }",
3372
3813
  "resultType": "PluginCoreTagsListComponentsResult"
3373
3814
  },
3815
+ {
3816
+ "path": "core.tags.listForComponent",
3817
+ "namespace": "core.tags",
3818
+ "summary": "List the tags carried by a component.",
3819
+ "examplePrompts": [
3820
+ "What tags does this space have?",
3821
+ "List the tags on component cmp_42",
3822
+ "Show the labels applied to this room\n\n# Example\n```ts\nconst { tags } = await snaptrude.core.tags.listForComponent(\"cmp_42\")\nfor (const t of tags) console.log(t.categoryName, t.tagName)\n```"
3823
+ ],
3824
+ "argsType": "ComponentHandle",
3825
+ "resultType": "PluginCoreTagsGetTagsForComponentResult"
3826
+ },
3374
3827
  {
3375
3828
  "path": "core.tags.unassign",
3376
3829
  "namespace": "core.tags",
@@ -3497,7 +3950,8 @@
3497
3950
  "Show me the full scene\n\n# Example\n```ts\nawait snaptrude.core.zoom.extents()\n```"
3498
3951
  ],
3499
3952
  "argsType": null,
3500
- "resultType": "boolean"
3953
+ "resultType": "boolean",
3954
+ "deprecated": "core.camera.zoomExtents"
3501
3955
  },
3502
3956
  {
3503
3957
  "path": "core.zoom.selection",
@@ -3510,7 +3964,8 @@
3510
3964
  "Fit the view to the selected room\n\n# Example\n```ts\nawait snaptrude.core.zoom.selection()\n```"
3511
3965
  ],
3512
3966
  "argsType": null,
3513
- "resultType": "boolean"
3967
+ "resultType": "boolean",
3968
+ "deprecated": "core.camera.zoomSelection"
3514
3969
  },
3515
3970
  {
3516
3971
  "path": "design.boolean.intersect",
@@ -3556,7 +4011,7 @@
3556
4011
  {
3557
4012
  "path": "design.create.beam",
3558
4013
  "namespace": "design.create",
3559
- "summary": "Create a **beam** by extruding a cross-section contour along `direction` by `length`.",
4014
+ "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.",
3560
4015
  "examplePrompts": [
3561
4016
  "Add a beam spanning 6 metres between the columns",
3562
4017
  "Create a horizontal beam along the X axis",
@@ -3566,6 +4021,19 @@
3566
4021
  "argsType": "ContourHandle",
3567
4022
  "resultType": "ComponentHandle"
3568
4023
  },
4024
+ {
4025
+ "path": "design.create.buildableEnvelope",
4026
+ "namespace": "design.create",
4027
+ "summary": "Create a new parametric buildable envelope — the zoning-regulated volume a building may occupy — generated from a site polygon, tiered setbacks, a height or floor-count cap, and optional FAR and lot-coverage limits. The host mints the envelope id and returns it. Canonical home of the create formerly at `entity.buildableEnvelope.create` (now deprecated).",
4028
+ "examplePrompts": [
4029
+ "Create a buildable envelope for my site",
4030
+ "Generate the zoning envelope with 10ft front setbacks",
4031
+ "Show the maximum buildable volume with a 150ft height limit",
4032
+ "Create a zoning envelope capped at 12 floors with FAR 3\n\n# Example\n```ts\nconst { buildableEnvelopeId } = await snaptrude.design.create.buildableEnvelope(\n[\n{ x: 0, z: 0 },\n{ x: 100, z: 0 },\n{ x: 100, z: 80 },\n{ x: 0, z: 80 },\n],\n\"ft\",\n[\n{ aboveHeight: 0, front: 10, side: 5, rear: 10 },\n{ aboveHeight: 100, front: 20, side: 10, rear: 20 },\n],\n{ kind: \"max_height\", maxHeight: 150 },\n12,\n)\n```"
4033
+ ],
4034
+ "argsType": "PluginBuildableEnvelopePolygonVertex[]",
4035
+ "resultType": "PluginBuildableEnvelopeCreateResult"
4036
+ },
3569
4037
  {
3570
4038
  "path": "design.create.ceiling",
3571
4039
  "namespace": "design.create",
@@ -3582,7 +4050,7 @@
3582
4050
  {
3583
4051
  "path": "design.create.column",
3584
4052
  "namespace": "design.create",
3585
- "summary": "Create a **column** by extruding a cross-section contour upward by `height` from a base `position`.",
4053
+ "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.",
3586
4054
  "examplePrompts": [
3587
4055
  "Add a 3m tall column at this point",
3588
4056
  "Place a column at the grid intersection",
@@ -3601,10 +4069,11 @@
3601
4069
  "Duplicate the selected furniture along the X axis",
3602
4070
  "Make 5 copies of this column at 4 metre intervals",
3603
4071
  "Array these walls with a 3m offset",
3604
- "Clone the desk as a unique copy, not an instance\n\n# Example\n```ts\nconst { vec3 } = snaptrude.core.math\nconst copies = await snaptrude.design.create.copy([\"space-id\"], vec3.new(6, 0, 0), { count: 3 })\n```"
4072
+ "Clone the desk as a unique copy, not an instance"
3605
4073
  ],
3606
4074
  "argsType": "ComponentHandle[]",
3607
- "resultType": "ComponentHandle[]"
4075
+ "resultType": "ComponentHandle[]",
4076
+ "performance": "To place N repeats of the same geometry, bulk-create the seed(s) once then call this ONCE with `{ count: N - 1 }` — one host round-trip for all copies. Never reproduce geometry by looping `design.create.*` N times. Copy only after the create that mints the seed ids. # Example ```ts const { vec3 } = snaptrude.core.math const copies = await snaptrude.design.create.copy([\"space-id\"], vec3.new(6, 0, 0), { count: 3 }) ```"
3608
4077
  },
3609
4078
  {
3610
4079
  "path": "design.create.door",
@@ -3615,7 +4084,8 @@
3615
4084
  "Place a sliding door on the selected wall",
3616
4085
  "Put a door from the catalog at this point on the wall",
3617
4086
  "Insert the entrance door into this wall",
3618
- "Add a door to the wall and call it Entry-01\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```"
4087
+ "Add a door to the wall and call it Entry-01",
4088
+ "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```"
3619
4089
  ],
3620
4090
  "argsType": "string",
3621
4091
  "resultType": "ComponentHandle"
@@ -3642,7 +4112,8 @@
3642
4112
  "Add a sofa from the furniture catalog to the living room",
3643
4113
  "Drop a desk into the scene at 3, 0, 5",
3644
4114
  "Insert the uploaded bed model in the bedroom",
3645
- "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```"
4115
+ "Put a table from my project library here and name it Table-01",
4116
+ "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```"
3646
4117
  ],
3647
4118
  "argsType": "string",
3648
4119
  "resultType": "ComponentHandle"
@@ -3661,13 +4132,25 @@
3661
4132
  "resultType": "ComponentHandle"
3662
4133
  },
3663
4134
  {
3664
- "path": "design.create.referenceLines",
4135
+ "path": "design.create.massFromBrep",
3665
4136
  "namespace": "design.create",
3666
- "summary": "Create **reference lines** from a profile one reference line per curve in the profile's ordered chain. Returns a handle per created line.",
4137
+ "summary": "Create a **mass** from a custom solid built with a `core.geom.create` brep constructor (`brepFromFaces`, `brepFromExtrusion`, `brepFromLoft`, `brepFromMesh`, or a brep boolean) — the free-form counterpart of {@linkcode PluginDesignCreateApi.mass}, for solids that are not simple footprint extrusions (pyramids, wedges, faceted volumes).",
3667
4138
  "examplePrompts": [
3668
- "Draw a reference line between these two points",
3669
- "Add dashed guide lines along this path",
3670
- "Create grid lines tagged A through the plan",
4139
+ "Create a mass from these faces",
4140
+ "Turn this custom brep into a scene mass",
4141
+ "Add a pyramid-shaped mass to the model\n\n# Example\n```ts\nconst apex = { x: 0, y: 4, z: 0 }\nconst a = { x: -2, y: 0, z: -2 }\nconst b = { x: 2, y: 0, z: -2 }\nconst c = { x: 2, y: 0, z: 2 }\nconst d = { x: -2, y: 0, z: 2 }\nconst brep = await snaptrude.core.geom.create.brepFromFaces([\n[a, d, c, b],\n[a, b, apex],\n[b, c, apex],\n[c, d, apex],\n[d, a, apex],\n])\nconst pyramid = await snaptrude.design.create.massFromBrep(brep, \"Pavilion\")\n```"
4142
+ ],
4143
+ "argsType": "BrepHandle",
4144
+ "resultType": "ComponentHandle"
4145
+ },
4146
+ {
4147
+ "path": "design.create.referenceLines",
4148
+ "namespace": "design.create",
4149
+ "summary": "Create **reference lines** from a profile — one reference line per curve in the profile's ordered chain. Returns a handle per created line.",
4150
+ "examplePrompts": [
4151
+ "Draw a reference line between these two points",
4152
+ "Add dashed guide lines along this path",
4153
+ "Create grid lines tagged A through the plan",
3671
4154
  "Set up construction lines for the column grid",
3672
4155
  "Mark a red reference line across the site\n\n# Example\n```ts\nconst v = snaptrude.core.math.vec3\nconst profile = await snaptrude.core.geom.create.profileFromLinePoints([\nawait v.new(0, 0, 0),\nawait v.new(10, 0, 0),\n])\nconst lines = await snaptrude.design.create.referenceLines(\nprofile,\nundefined,\nundefined,\n\"DASHED\",\n)\n```"
3673
4156
  ],
@@ -3724,23 +4207,27 @@
3724
4207
  "Add a new space on the current storey using this footprint",
3725
4208
  "Make a bedroom here and assign it to the Residential department",
3726
4209
  "Extrude this closed outline into a 10 foot high room",
3727
- "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```"
4210
+ "Can you create a Kitchen space from the sketch I just drew?",
4211
+ "Create a bedroom on the second floor from this outline"
3728
4212
  ],
3729
4213
  "argsType": "ContourHandle",
3730
- "resultType": "ComponentHandle"
4214
+ "resultType": "ComponentHandle",
4215
+ "performance": "For MORE THAN ONE space, call `design.create.spaces(items[])` — the whole batch is one host round-trip. Looping this single-space creator is N round-trips (slow, and a large loop can trip the plugin rate limit). # Example ```ts const v = snaptrude.core.math.vec3 const outer = await snaptrude.core.geom.create.profileFromLinePoints([ await v.new(0, 0, 0), await v.new(10, 0, 0), await v.new(10, 0, 8), await v.new(0, 0, 8), ]) const contour = await snaptrude.core.geom.create.contourFromProfile(outer) const space = await snaptrude.design.create.space(contour, 3, \"Living\") // …place one directly on the second floor (no setActive dance): const upstairs = await snaptrude.design.create.space( contour, 3, \"Bedroom\", undefined, undefined, undefined, undefined, 2, ) ```"
3731
4216
  },
3732
4217
  {
3733
4218
  "path": "design.create.spaces",
3734
4219
  "namespace": "design.create",
3735
- "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.",
4220
+ "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.",
3736
4221
  "examplePrompts": [
3737
4222
  "Create several rooms at once from these footprints",
3738
4223
  "Generate all the bedrooms in one operation",
3739
4224
  "Bulk create the spaces for this floor plan",
3740
- "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```"
4225
+ "Add three rooms with different heights in a single undo step",
4226
+ "Create one room on the ground floor and one on the first floor"
3741
4227
  ],
3742
4228
  "argsType": "PluginCreateSpaceItem[]",
3743
- "resultType": "ComponentHandle[]"
4229
+ "resultType": "ComponentHandle[]",
4230
+ "performance": "Bulk creator — the whole batch is ONE host round-trip. Always prefer this over calling `design.create.space` in a loop: build the full `items[]` array first (all per-item math and geometry up front), then make one call. # Example ```ts const rect = await snaptrude.core.geom.create.profileRect(4, 3) const contour = await snaptrude.core.geom.create.contourFromProfile(rect) const [a, b] = await snaptrude.design.create.spaces([ { contour, height: 3, label: \"R1\" }, { contour, height: 4, label: \"R2\", position: await vec3.new(10, 0, 0) }, ]) ```"
3744
4231
  },
3745
4232
  {
3746
4233
  "path": "design.create.staircase",
@@ -3765,7 +4252,9 @@
3765
4252
  "Create 3m high, 200mm thick walls from these points",
3766
4253
  "Build a wall run around the room outline",
3767
4254
  "Turn this polyline sketch into walls",
3768
- "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```"
4255
+ "Add walls with mitred corners along the path",
4256
+ "Draw brick walls with plaster along this outline",
4257
+ "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```"
3769
4258
  ],
3770
4259
  "argsType": "ProfileHandle",
3771
4260
  "resultType": "ComponentHandle[]"
@@ -3779,7 +4268,8 @@
3779
4268
  "Place a casement window on the selected wall",
3780
4269
  "Put a window from the catalog at this point on the wall",
3781
4270
  "Insert a window into the living room wall",
3782
- "Add a window to the wall and name it Win-01\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```"
4271
+ "Add a window to the wall and name it Win-01",
4272
+ "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```"
3783
4273
  ],
3784
4274
  "argsType": "string",
3785
4275
  "resultType": "ComponentHandle"
@@ -3793,10 +4283,11 @@
3793
4283
  "Remove these walls from the model",
3794
4284
  "Get rid of this mass entirely",
3795
4285
  "Delete all the furniture I picked",
3796
- "Remove the door and window I just created\n\n# Example\n```ts\n// Hard-delete every furniture item on storey 2 (a single undo entry)\nconst furniture = await snaptrude.design.query.listFurniture({ storeys: [2] })\nif (furniture.length > 0) {\nconst { affected } = await snaptrude.design.delete.entities(furniture)\n}\n```"
4286
+ "Remove the door and window I just created"
3797
4287
  ],
3798
4288
  "argsType": "ComponentHandle[]",
3799
- "resultType": "PluginDesignChangeResult"
4289
+ "resultType": "PluginDesignChangeResult",
4290
+ "performance": "Array delete — pass every target in one call (one host round-trip). There is no per-item delete; collect the whole set and never loop this per entity. # Example ```ts // Hard-delete every furniture item on storey 2 (a single undo entry) const furniture = await snaptrude.design.query.listFurniture({ storeys: [2] }) if (furniture.length > 0) { const { affected } = await snaptrude.design.delete.entities(furniture) } ```"
3800
4291
  },
3801
4292
  {
3802
4293
  "path": "design.doors.exists",
@@ -4217,6 +4708,20 @@
4217
4708
  "argsType": "PluginMaterialSpec",
4218
4709
  "resultType": "MaterialHandle"
4219
4710
  },
4711
+ {
4712
+ "path": "design.materials.get",
4713
+ "namespace": "design.materials",
4714
+ "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.",
4715
+ "examplePrompts": [
4716
+ "What material is on this wall?",
4717
+ "Eyedrop the finish of the selected object",
4718
+ "Which material does this slab use?",
4719
+ "Read the material on this column so I can paint others with it",
4720
+ "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```"
4721
+ ],
4722
+ "argsType": "ComponentHandle",
4723
+ "resultType": "PluginComponentMaterial | null"
4724
+ },
4220
4725
  {
4221
4726
  "path": "design.materials.getByFace",
4222
4727
  "namespace": "design.materials",
@@ -4297,15 +4802,14 @@
4297
4802
  {
4298
4803
  "path": "design.materials.list",
4299
4804
  "namespace": "design.materials",
4300
- "summary": "List the project materials.",
4805
+ "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}.",
4301
4806
  "examplePrompts": [
4302
4807
  "List all the materials in this project",
4303
4808
  "What materials do I have available to apply?",
4304
- "Show me the preset materials library",
4305
4809
  "Which finishes exist in this model?",
4306
- "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```"
4810
+ "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```"
4307
4811
  ],
4308
- "argsType": "\"project\" | \"preset\"",
4812
+ "argsType": null,
4309
4813
  "resultType": "MaterialHandle[]"
4310
4814
  },
4311
4815
  {
@@ -4320,6 +4824,19 @@
4320
4824
  "argsType": "ComponentHandle",
4321
4825
  "resultType": "PluginFaceMaterial[]"
4322
4826
  },
4827
+ {
4828
+ "path": "design.materials.listPresets",
4829
+ "namespace": "design.materials",
4830
+ "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 }`.",
4831
+ "examplePrompts": [
4832
+ "Show me the preset materials library",
4833
+ "What wood finishes are available in the material library?",
4834
+ "Browse the material catalog and apply a brick texture",
4835
+ "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```"
4836
+ ],
4837
+ "argsType": null,
4838
+ "resultType": "PluginPresetMaterial[]"
4839
+ },
4323
4840
  {
4324
4841
  "path": "design.materials.reset",
4325
4842
  "namespace": "design.materials",
@@ -4399,6 +4916,19 @@
4399
4916
  "argsType": "ComponentHandle",
4400
4917
  "resultType": "CurveHandle | null"
4401
4918
  },
4919
+ {
4920
+ "path": "design.query.geometry.getTriangulatedMeshes",
4921
+ "namespace": "design.query.geometry",
4922
+ "summary": "Get the **triangulated render meshes** of scene components as plain, serializable arrays — flat world-space vertex `positions` (`[x0, y0, z0, x1, …]`) and triangle `indices` (three per triangle), one record per requested component.",
4923
+ "examplePrompts": [
4924
+ "Export the selected masses as a triangle mesh",
4925
+ "Get the raw vertices and triangles of this wall in world coordinates",
4926
+ "Give me the triangulated geometry of every space with its materials",
4927
+ "Compute the surface area of this roof from its triangles"
4928
+ ],
4929
+ "argsType": "ComponentHandle[]",
4930
+ "resultType": "PluginDesignQueryGeometryGetTriangulatedMeshesResult"
4931
+ },
4402
4932
  {
4403
4933
  "path": "design.query.getBoundingBox",
4404
4934
  "namespace": "design.query",
@@ -4479,10 +5009,11 @@
4479
5009
  {
4480
5010
  "path": "design.query.getProperties",
4481
5011
  "namespace": "design.query",
4482
- "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`).",
5012
+ "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)`.",
4483
5013
  "examplePrompts": [
4484
5014
  "Show me all the details of the selected object",
4485
5015
  "What storey is this wall on?",
5016
+ "Which wall type is assigned to this wall?",
4486
5017
  "Which department does this room belong to?",
4487
5018
  "Is this element locked or hidden?",
4488
5019
  "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```"
@@ -4747,13 +5278,28 @@
4747
5278
  "examplePrompts": [
4748
5279
  "What's the area of this room?",
4749
5280
  "How long is the selected wall?",
5281
+ "How thick is this wall?",
5282
+ "Get the thickness of the slab on level 2",
4750
5283
  "Get the volume of this mass",
4751
5284
  "Give me the dimensions of the selected element",
4752
- "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```"
5285
+ "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```"
4753
5286
  ],
4754
5287
  "argsType": "ComponentHandle",
4755
5288
  "resultType": "PluginEntityMeasurements | null"
4756
5289
  },
5290
+ {
5291
+ "path": "design.query.referenceLines.get",
5292
+ "namespace": "design.query.referenceLines",
5293
+ "summary": "Get properties of a reference line by its ID.",
5294
+ "examplePrompts": [
5295
+ "Get the curve geometry of this reference line",
5296
+ "Where does this grid line run?",
5297
+ "Read the geometry of a guide line by its id",
5298
+ "Look up the curve of the selected reference line\n\n# Example\n```ts\nconst [refLine] = await snaptrude.design.query.listReferenceLines()\nconst result = await snaptrude.design.query.referenceLines.get(refLine, [\"curve\"])\n// result.curve is an opaque CurveHandle; read its coordinates via\n// `snaptrude.core.geom.curve`.\n```"
5299
+ ],
5300
+ "argsType": "string",
5301
+ "resultType": "PluginReferenceLineGetResult"
5302
+ },
4757
5303
  {
4758
5304
  "path": "design.query.spaces.get",
4759
5305
  "namespace": "design.query.spaces",
@@ -4768,6 +5314,19 @@
4768
5314
  "argsType": "ComponentHandle",
4769
5315
  "resultType": "PluginDesignQuerySpacesGetResult"
4770
5316
  },
5317
+ {
5318
+ "path": "design.query.spaces.getEnclosure",
5319
+ "namespace": "design.query.spaces",
5320
+ "summary": "Get the **enclosure** of a space — the floor and ceiling that cap it, the bounding walls around it (with each wall's door/window openings), and the neighbouring spaces it shares a boundary with.",
5321
+ "examplePrompts": [
5322
+ "What walls, floor and ceiling enclose this room?",
5323
+ "Which of this room's walls are external?",
5324
+ "List the doors and windows around the selected space",
5325
+ "Which spaces are adjacent to this room, and through which wall?\n\n# Example\n```ts\nconst [space] = await snaptrude.design.query.listSpaces()\nconst enclosure = await snaptrude.design.query.spaces.getEnclosure(space)\nif (enclosure) {\nconst walls = enclosure.surfaces.filter((s) => s.role === \"wall\")\nconst external = walls.filter((s) => s.isExternal)\nconsole.log(`${walls.length} walls, ${external.length} external`)\n}\n```"
5326
+ ],
5327
+ "argsType": "ComponentHandle",
5328
+ "resultType": "PluginSpaceEnclosure | null"
5329
+ },
4771
5330
  {
4772
5331
  "path": "design.query.spaces.getFootprint",
4773
5332
  "namespace": "design.query.spaces",
@@ -4871,10 +5430,11 @@
4871
5430
  "Line up these masses along their top edges",
4872
5431
  "Center these columns horizontally",
4873
5432
  "Align all the walls to the left edge of this reference wall",
4874
- "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```"
5433
+ "Snap the bottom edges of these spaces together"
4875
5434
  ],
4876
5435
  "argsType": "ComponentHandle[]",
4877
- "resultType": "PluginDesignChangeResult"
5436
+ "resultType": "PluginDesignChangeResult",
5437
+ "performance": "Array API — one host round-trip for the whole set. Pass every target in a single call; never loop `design.transform.align` per entity. # Example ```ts const rooms = await snaptrude.design.selection.get() // align every room's left (world -X) edge to a common minimum await snaptrude.design.transform.align(rooms, \"left\") // …or align them to a fixed reference component's left edge const [anchor] = await snaptrude.design.query.listWalls({ storeys: [1] }) await snaptrude.design.transform.align(rooms, \"left\", { reference: anchor }) ```"
4878
5438
  },
4879
5439
  {
4880
5440
  "path": "design.transform.mirror",
@@ -4885,10 +5445,11 @@
4885
5445
  "Flip these rooms left to right",
4886
5446
  "Mirror this furniture block horizontally",
4887
5447
  "Flip the selected walls front to back",
4888
- "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```"
5448
+ "Create a mirror image of these masses about the z axis"
4889
5449
  ],
4890
5450
  "argsType": "ComponentHandle[]",
4891
- "resultType": "PluginDesignChangeResult"
5451
+ "resultType": "PluginDesignChangeResult",
5452
+ "performance": "Array API — one host round-trip for the whole set. Pass every target in a single call; never loop `design.transform.mirror` per entity. # Example ```ts const rooms = await snaptrude.design.selection.get() await snaptrude.design.transform.mirror(rooms, \"x\") ```"
4892
5453
  },
4893
5454
  {
4894
5455
  "path": "design.transform.move",
@@ -4899,23 +5460,26 @@
4899
5460
  "Shift these walls 3m along the x axis",
4900
5461
  "Nudge this space 500mm north",
4901
5462
  "Translate the furniture block by (10, 0, 5)",
4902
- "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```"
5463
+ "Move these masses up one storey"
4903
5464
  ],
4904
5465
  "argsType": "ComponentHandle[]",
4905
- "resultType": "PluginDesignChangeResult"
5466
+ "resultType": "PluginDesignChangeResult",
5467
+ "performance": "Array API — one host round-trip for the whole set. Pass every target in a single call; never loop `design.transform.move` per entity. # Example ```ts const { vec3 } = snaptrude.core.math await snaptrude.design.transform.move([\"space-id\"], vec3.new(10, 0, 0)) ```"
4906
5468
  },
4907
5469
  {
4908
5470
  "path": "design.transform.rotate",
4909
5471
  "namespace": "design.transform",
4910
- "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.",
5472
+ "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.",
4911
5473
  "examplePrompts": [
4912
5474
  "Rotate the selected building 90 degrees",
4913
5475
  "Turn this room 45 degrees clockwise",
4914
5476
  "Spin the furniture block 180 degrees about its centre",
4915
- "Rotate these masses 30 degrees around the vertical axis\n\n# Example\n```ts\nawait snaptrude.design.transform.rotate([\"space-id\"], 90)\n```"
5477
+ "Rotate these masses 30 degrees around the vertical axis",
5478
+ "Rotate these walls 90 degrees about the origin"
4916
5479
  ],
4917
5480
  "argsType": "ComponentHandle[]",
4918
- "resultType": "PluginDesignChangeResult"
5481
+ "resultType": "PluginDesignChangeResult",
5482
+ "performance": "Array API — one host round-trip for the whole set. Pass every target in a single call; never loop `design.transform.rotate` per entity. # Example ```ts await snaptrude.design.transform.rotate([\"space-id\"], 90) // …or rotate about an explicit pivot point const { vec3 } = snaptrude.core.math await snaptrude.design.transform.rotate([\"space-id\"], 90, { pivot: vec3.new(0, 0, 0) }) ```"
4919
5483
  },
4920
5484
  {
4921
5485
  "path": "design.types.get",
@@ -4969,10 +5533,23 @@
4969
5533
  "argsType": "ComponentHandle[]",
4970
5534
  "resultType": "PluginDesignChangeResult"
4971
5535
  },
5536
+ {
5537
+ "path": "design.update.buildableEnvelope",
5538
+ "namespace": "design.update",
5539
+ "summary": "Update an existing parametric buildable envelope — regenerate the zoning volume from a revised site polygon, setbacks, vertical cap, or FAR and lot-coverage limits, keeping the same envelope id. Canonical home of the update formerly at `entity.buildableEnvelope.update` (now deprecated).",
5540
+ "examplePrompts": [
5541
+ "Change the envelope's height limit to 175 feet",
5542
+ "Update the setbacks on the buildable envelope",
5543
+ "Regenerate the zoning envelope with a new site boundary",
5544
+ "Increase the FAR on the buildable volume\n\n# Example\n```ts\nconst { buildableEnvelopeId } = await snaptrude.design.update.buildableEnvelope(\nexistingId,\n[\n{ x: 0, z: 0 },\n{ x: 100, z: 0 },\n{ x: 100, z: 80 },\n{ x: 0, z: 80 },\n],\n\"ft\",\n[{ aboveHeight: 0, front: 10, side: 5, rear: 10 }],\n{ kind: \"max_height\", maxHeight: 175 },\n12,\n)\n```"
5545
+ ],
5546
+ "argsType": "string",
5547
+ "resultType": "PluginBuildableEnvelopeUpdateResult"
5548
+ },
4972
5549
  {
4973
5550
  "path": "design.update.ceiling",
4974
5551
  "namespace": "design.update",
4975
- "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`.",
5552
+ "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`.",
4976
5553
  "examplePrompts": [
4977
5554
  "Make this ceiling 150mm thick",
4978
5555
  "Set every ceiling to a 100 thickness",
@@ -4984,7 +5561,7 @@
4984
5561
  {
4985
5562
  "path": "design.update.floor",
4986
5563
  "namespace": "design.update",
4987
- "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`.",
5564
+ "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`.",
4988
5565
  "examplePrompts": [
4989
5566
  "Make this floor 200mm thick",
4990
5567
  "Set every floor to a 250 thickness",
@@ -4996,11 +5573,12 @@
4996
5573
  {
4997
5574
  "path": "design.update.roof",
4998
5575
  "namespace": "design.update",
4999
- "summary": "Edit a **roof's** thickness — the slab-family updater for roofs (shares the slab thickness command). Undoable. Thickness is in **engine units** (the `design.doors.setWidth` convention) and must be `> 0`.",
5576
+ "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.",
5000
5577
  "examplePrompts": [
5001
5578
  "Make this roof 300mm thick",
5002
5579
  "Set the roof slab thickness to 250",
5003
- "Thicken every roof to 350\n\n# Example\n```ts\nconst [roof] = await snaptrude.design.query.listRoofs()\nawait snaptrude.design.update.roof(roof, { thickness: 300 })\n```"
5580
+ "Give the roof a 600 overhang",
5581
+ "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```"
5004
5582
  ],
5005
5583
  "argsType": "ComponentHandle",
5006
5584
  "resultType": "PluginDesignChangeResult"
@@ -5044,14 +5622,28 @@
5044
5622
  "argsType": "ComponentHandle",
5045
5623
  "resultType": "boolean"
5046
5624
  },
5625
+ {
5626
+ "path": "design.update.setStorey",
5627
+ "namespace": "design.update",
5628
+ "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**.",
5629
+ "examplePrompts": [
5630
+ "Move this sofa to storey 2",
5631
+ "Put the selected walls on the first basement level",
5632
+ "Send everything on this storey up one level",
5633
+ "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```"
5634
+ ],
5635
+ "argsType": "ComponentHandle[]",
5636
+ "resultType": "PluginDesignChangeResult"
5637
+ },
5047
5638
  {
5048
5639
  "path": "design.update.slab",
5049
5640
  "namespace": "design.update",
5050
- "summary": "Edit a **slab's** thickness — the same command the properties panel's Thickness field drives. Undoable; the slab rebuilds and dimension lines refresh. The thickness is in **engine units** (the same convention as `design.doors.setWidth`) and must be `> 0`.",
5641
+ "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.",
5051
5642
  "examplePrompts": [
5052
5643
  "Set this slab's thickness to 250mm",
5053
5644
  "Make the floor slab 300 thick",
5054
- "Thicken every slab on level 2 to 200\n\n# Example\n```ts\nconst [slab] = await snaptrude.design.query.listSlabs()\nawait snaptrude.design.update.slab(slab, { thickness: 250 })\n```"
5645
+ "Give this slab a 200 overhang",
5646
+ "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```"
5055
5647
  ],
5056
5648
  "argsType": "ComponentHandle",
5057
5649
  "resultType": "PluginDesignChangeResult"
@@ -5065,10 +5657,11 @@
5065
5657
  "Change this space's room type to Meeting Room",
5066
5658
  "Set the height of this room to 3 metres",
5067
5659
  "Move this space into the Circulation department",
5068
- "Exclude this room from the area calculations\n\n# Example\n```ts\nawait snaptrude.design.update.space(\"space-id\", { properties: { room_type: \"Office\" } })\n```"
5660
+ "Exclude this room from the area calculations"
5069
5661
  ],
5070
5662
  "argsType": "ComponentHandle",
5071
- "resultType": "PluginSpaceUpdateResult"
5663
+ "resultType": "PluginSpaceUpdateResult",
5664
+ "performance": "For MORE THAN ONE space, call `design.update.spaces(items[])` — the whole batch is one host round-trip. Looping this single-space updater is N round-trips. # Example ```ts await snaptrude.design.update.space(\"space-id\", { properties: { room_type: \"Office\" } }) ```"
5072
5665
  },
5073
5666
  {
5074
5667
  "path": "design.update.spaces",
@@ -5079,10 +5672,11 @@
5079
5672
  "Change the room type of these five spaces at once",
5080
5673
  "Set every room on this floor to a 3m height in one go",
5081
5674
  "Bulk-assign these spaces to the Service department",
5082
- "Mark all of these rooms as excluded from area in one update\n\n# Example\n```ts\n// Re-label every selected room and mark it NET area — one undoable bulk update\nconst rooms = await snaptrude.design.query.listSpaces({ isSelected: true })\nconst results = await snaptrude.design.update.spaces(\nrooms.map((space) => ({\nspace,\nproperties: { room_type: \"Bedroom\", areaClass: \"NET\" },\n})),\n)\n// One result per item, in input order\nconsole.log(results.map((r) => r.spaceId))\n```"
5675
+ "Mark all of these rooms as excluded from area in one update"
5083
5676
  ],
5084
5677
  "argsType": "PluginUpdateSpaceItem[]",
5085
- "resultType": "PluginSpaceUpdateResult[]"
5678
+ "resultType": "PluginSpaceUpdateResult[]",
5679
+ "performance": "Bulk update — the whole batch is ONE host round-trip. Prefer over looping `design.update.space`: build the `items[]` array first, then make one call. # Example ```ts // Re-label every selected room and mark it NET area — one undoable bulk update const rooms = await snaptrude.design.query.listSpaces({ isSelected: true }) const results = await snaptrude.design.update.spaces( rooms.map((space) => ({ space, properties: { room_type: \"Bedroom\", areaClass: \"NET\" }, })), ) // One result per item, in input order console.log(results.map((r) => r.spaceId)) ```"
5086
5680
  },
5087
5681
  {
5088
5682
  "path": "design.update.staircase",
@@ -5101,13 +5695,13 @@
5101
5695
  {
5102
5696
  "path": "design.update.wall",
5103
5697
  "namespace": "design.update",
5104
- "summary": "Edit a **wall's** dimensions — its thickness and/or height the same command the properties panel's Thickness/Height fields drive. 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.",
5698
+ "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.",
5105
5699
  "examplePrompts": [
5106
5700
  "Make this wall 230mm thick",
5107
5701
  "Set the selected wall's height to 3 metres",
5108
5702
  "Thicken every exterior wall to 300",
5109
- "Raise all the walls on this floor to 3200 tall",
5110
- "Change this partition to 100mm thick and 2700 high\n\n# Example\n```ts\n// Standardise every wall on storey 1 to a 230mm thickness\nconst walls = await snaptrude.design.query.listWalls({ storeys: [1] })\nfor (const wall of walls) {\nawait snaptrude.design.update.wall(wall, { thickness: 230 })\n}\n```"
5703
+ "Change this wall to a Glass Wall",
5704
+ "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```"
5111
5705
  ],
5112
5706
  "argsType": "ComponentHandle",
5113
5707
  "resultType": "PluginDesignChangeResult"
@@ -5294,7 +5888,8 @@
5294
5888
  "Create a zoning envelope capped at 12 floors with FAR 3\n\n# Example\n```ts\nconst { buildableEnvelopeId } = await snaptrude.entity.buildableEnvelope.create(\n[\n{ x: 0, z: 0 },\n{ x: 100, z: 0 },\n{ x: 100, z: 80 },\n{ x: 0, z: 80 },\n],\n\"ft\",\n[\n{ aboveHeight: 0, front: 10, side: 5, rear: 10 },\n{ aboveHeight: 100, front: 20, side: 10, rear: 20 },\n],\n{ kind: \"max_height\", maxHeight: 150 },\n12,\n)\n```"
5295
5889
  ],
5296
5890
  "argsType": "PluginBuildableEnvelopePolygonVertex[]",
5297
- "resultType": "PluginBuildableEnvelopeCreateResult"
5891
+ "resultType": "PluginBuildableEnvelopeCreateResult",
5892
+ "deprecated": "design.create.buildableEnvelope"
5298
5893
  },
5299
5894
  {
5300
5895
  "path": "entity.buildableEnvelope.update",
@@ -5308,7 +5903,8 @@
5308
5903
  "Modify the envelope to allow 15 storeys instead\n\n# Example\n```ts\nconst { buildableEnvelopeId } = await snaptrude.entity.buildableEnvelope.update(\nexistingId,\n[\n{ x: 0, z: 0 },\n{ x: 100, z: 0 },\n{ x: 100, z: 80 },\n{ x: 0, z: 80 },\n],\n\"ft\",\n[{ aboveHeight: 0, front: 10, side: 5, rear: 10 }],\n{ kind: \"max_height\", maxHeight: 175 },\n12,\n)\n```"
5309
5904
  ],
5310
5905
  "argsType": "string",
5311
- "resultType": "PluginBuildableEnvelopeUpdateResult"
5906
+ "resultType": "PluginBuildableEnvelopeUpdateResult",
5907
+ "deprecated": "design.update.buildableEnvelope"
5312
5908
  },
5313
5909
  {
5314
5910
  "path": "entity.referenceLine.createMulti",
@@ -5322,7 +5918,8 @@
5322
5918
  "Turn this profile into reference lines\n\n# Example\n```ts\nconst { vec3 } = snaptrude.core.math\n\nconst start = await vec3.new(0, 0, 0)\nconst mid = await vec3.new(10, 0, 0)\nconst end = await vec3.new(10, 0, 10)\nconst l1 = await snaptrude.core.geom.create.line(start, mid)\nconst l2 = await snaptrude.core.geom.create.line(mid, end)\nconst profile = await snaptrude.core.geom.create.profileFromCurves([l1, l2])\n\nconst { referenceLineIds } = await snaptrude.entity.referenceLine.createMulti(profile)\n```"
5323
5919
  ],
5324
5920
  "argsType": "ProfileHandle",
5325
- "resultType": "PluginReferenceLineCreateMultiResult"
5921
+ "resultType": "PluginReferenceLineCreateMultiResult",
5922
+ "deprecated": "design.create.referenceLines"
5326
5923
  },
5327
5924
  {
5328
5925
  "path": "entity.referenceLine.delete",
@@ -5335,7 +5932,8 @@
5335
5932
  "Erase a reference line by its id\n\n# Example\n```ts\nawait snaptrude.entity.referenceLine.delete(\"some-ref-line-id\")\n```"
5336
5933
  ],
5337
5934
  "argsType": "string",
5338
- "resultType": "PluginReferenceLineDeleteResult"
5935
+ "resultType": "PluginReferenceLineDeleteResult",
5936
+ "deprecated": "design.delete.entities"
5339
5937
  },
5340
5938
  {
5341
5939
  "path": "entity.referenceLine.get",
@@ -5348,7 +5946,8 @@
5348
5946
  "Look up the curve of the selected reference line\n\n# Example\n```ts\nconst result = await snaptrude.entity.referenceLine.get(\"some-ref-line-id\", [\"curve\"])\n// result.curve is an opaque CurveHandle; a dedicated curve read API for its\n// coordinates is exposed separately via `snaptrude.core.geom.curve`.\n```"
5349
5947
  ],
5350
5948
  "argsType": "string",
5351
- "resultType": "PluginReferenceLineGetResult"
5949
+ "resultType": "PluginReferenceLineGetResult",
5950
+ "deprecated": "design.query.referenceLines.get"
5352
5951
  },
5353
5952
  {
5354
5953
  "path": "entity.referenceLine.getAll",
@@ -5361,7 +5960,8 @@
5361
5960
  "Do I have any reference lines in this project?\n\n# Example\n```ts\nconst { referenceLineIds } = await snaptrude.entity.referenceLine.getAll()\nconsole.log(`Project has ${referenceLineIds.length} reference lines`)\n```"
5362
5961
  ],
5363
5962
  "argsType": null,
5364
- "resultType": "PluginReferenceLineGetAllResult"
5963
+ "resultType": "PluginReferenceLineGetAllResult",
5964
+ "deprecated": "design.query.listReferenceLines"
5365
5965
  },
5366
5966
  {
5367
5967
  "path": "entity.story.create",
@@ -5375,7 +5975,8 @@
5375
5975
  "Add another floor on top of the building\n\n# Example\n```ts\n// Create a new third floor with custom height\nconst { storyId } = await snaptrude.entity.story.create(3, 4.5)\n```"
5376
5976
  ],
5377
5977
  "argsType": "number",
5378
- "resultType": "PluginStoryCreateResult"
5978
+ "resultType": "PluginStoryCreateResult",
5979
+ "deprecated": "core.storeys.create"
5379
5980
  },
5380
5981
  {
5381
5982
  "path": "entity.story.delete",
@@ -5388,7 +5989,8 @@
5388
5989
  "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```"
5389
5990
  ],
5390
5991
  "argsType": "number",
5391
- "resultType": "PluginStoryDeleteResult"
5992
+ "resultType": "PluginStoryDeleteResult",
5993
+ "deprecated": "core.storeys.delete"
5392
5994
  },
5393
5995
  {
5394
5996
  "path": "entity.story.duplicate",
@@ -5398,10 +6000,12 @@
5398
6000
  "Duplicate this floor to the storey above",
5399
6001
  "Copy the ground floor down into a new basement",
5400
6002
  "Repeat this level upwards with its own independent geometry",
5401
- "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```"
6003
+ "Duplicate just the selected walls onto the next floor up"
5402
6004
  ],
5403
6005
  "argsType": "\"up\" | \"down\"",
5404
- "resultType": "PluginStoryDuplicateResult"
6006
+ "resultType": "PluginStoryDuplicateResult",
6007
+ "performance": "For storeys that share a layout, duplicate the storey instead of recreating its contents floor by floor — this copies every eligible element in one call, and the default instanced copies keep the floors linked. To stack many identical floors, either call this per level or capture the storey's component ids and `design.create.copy(ids, oneFloorRise, { count })` to lay them all down in a single call. # Example ```ts // Duplicate the whole active story one level up (instanced copies). const { targetStories, created, skipped } = await snaptrude.entity.story.duplicate(\"up\") console.log(`Copied ${created.length} elements onto story ${targetStories}`) if (skipped) console.log(`${skipped} elements were skipped`) ```",
6008
+ "deprecated": "core.storeys.copy"
5405
6009
  },
5406
6010
  {
5407
6011
  "path": "entity.story.get",
@@ -5415,7 +6019,8 @@
5415
6019
  "Show me the name and height of story 2\n\n# Example\n```ts\nconst info = await snaptrude.entity.story.get(1, [\"height\", \"name\", \"spacesCount\"])\nconsole.log(info.name, info.height, info.spacesCount)\n```"
5416
6020
  ],
5417
6021
  "argsType": "number",
5418
- "resultType": "PluginStoryGetResult"
6022
+ "resultType": "PluginStoryGetResult",
6023
+ "deprecated": "core.storeys.get"
5419
6024
  },
5420
6025
  {
5421
6026
  "path": "entity.story.getAll",
@@ -5428,7 +6033,8 @@
5428
6033
  "Which stories exist in this model?\n\n# Example\n```ts\nconst { stories } = await snaptrude.entity.story.getAll()\nfor (const s of stories) {\nconsole.log(`Story ${s.value}: ${s.name} (id: ${s.id})`)\n}\n```"
5429
6034
  ],
5430
6035
  "argsType": null,
5431
- "resultType": "PluginStoryGetAllResult"
6036
+ "resultType": "PluginStoryGetAllResult",
6037
+ "deprecated": "core.storeys.list"
5432
6038
  },
5433
6039
  {
5434
6040
  "path": "entity.story.setActive",
@@ -5441,7 +6047,8 @@
5441
6047
  "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```"
5442
6048
  ],
5443
6049
  "argsType": "number",
5444
- "resultType": "PluginStorySetActiveResult"
6050
+ "resultType": "PluginStorySetActiveResult",
6051
+ "deprecated": "core.storeys.setActive"
5445
6052
  },
5446
6053
  {
5447
6054
  "path": "entity.story.update",
@@ -5455,7 +6062,41 @@
5455
6062
  "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```"
5456
6063
  ],
5457
6064
  "argsType": "number",
5458
- "resultType": "PluginStoryUpdateResult"
6065
+ "resultType": "PluginStoryUpdateResult",
6066
+ "deprecated": "core.storeys.update"
6067
+ },
6068
+ {
6069
+ "path": "presentation.aiInspiration.cancelJob",
6070
+ "namespace": "presentation.aiInspiration",
6071
+ "summary": "Cancel a transient AI Inspiration job.",
6072
+ "examplePrompts": [
6073
+ "Cancel the running generation",
6074
+ "Stop that AI job\n\n# Example\n```ts\nconst { job } = await snaptrude.presentation.aiInspiration.cancelJob({ jobId })\nconsole.log(job.status) // \"cancelled\" (or a terminal state it already reached)\n```"
6075
+ ],
6076
+ "argsType": "PluginAIInspirationJobArgs",
6077
+ "resultType": "PluginAIInspirationCancelJobResult"
6078
+ },
6079
+ {
6080
+ "path": "presentation.aiInspiration.deleteRecipe",
6081
+ "namespace": "presentation.aiInspiration",
6082
+ "summary": "Delete a project-level AI Inspiration recipe.",
6083
+ "examplePrompts": [
6084
+ "Delete the facade render recipe",
6085
+ "Remove that saved AI recipe\n\n# Example\n```ts\nconst { recipes } = await snaptrude.presentation.aiInspiration.listRecipes()\nconst stale = recipes.find((r) => r.name === \"Old style test\")\nif (stale) {\nconst { deleted } = await snaptrude.presentation.aiInspiration.deleteRecipe({ recipeId: stale.id })\nconsole.log(deleted)\n}\n```"
6086
+ ],
6087
+ "argsType": "PluginAIInspirationDeleteRecipeArgs",
6088
+ "resultType": "PluginAIInspirationDeleteRecipeResult"
6089
+ },
6090
+ {
6091
+ "path": "presentation.aiInspiration.extractRecipeFromShape",
6092
+ "namespace": "presentation.aiInspiration",
6093
+ "summary": "Extract a reusable recipe draft from the workflow path ending at a shape.",
6094
+ "examplePrompts": [
6095
+ "Turn this workflow into a reusable recipe",
6096
+ "Save the generation steps behind this image\n\n# Example\n```ts\nconst extraction = await snaptrude.presentation.aiInspiration.extractRecipeFromShape({\nshapeId: selected.shapeId,\n})\nif (extraction.status === \"ready\") console.log(extraction.draft.summary)\n```"
6097
+ ],
6098
+ "argsType": "PluginAIInspirationExtractRecipeFromShapeArgs",
6099
+ "resultType": "PluginAIInspirationExtractionResult"
5459
6100
  },
5460
6101
  {
5461
6102
  "path": "presentation.aiInspiration.generate",
@@ -5466,11 +6107,90 @@
5466
6107
  "Render the selected view as a photorealistic image",
5467
6108
  "Make an AI image of a modern facade from this source",
5468
6109
  "Generate a video from this image",
5469
- "Turn this massing into a rendered street view\n\n# Example\n```ts\nconst { sources } = await snaptrude.presentation.aiInspiration.listSources({})\nconst [source, ...refs] = sources\nconst { outputs } = await snaptrude.presentation.aiInspiration.generate({\nsourceShapeId: source.shapeId,\nprompt: \"Photorealistic render of a modern timber facade at dusk\",\nreferenceShapeIds: refs.slice(0, 2).map((r) => r.shapeId),\nreferenceStrength: \"medium\",\n})\nfor (const out of outputs) console.log(out.outputType, out.shapeId, out.outputUrl)\n```"
6110
+ "Turn this massing into a rendered street view\n\n# Example\n```ts\nconst { sources } = await snaptrude.presentation.aiInspiration.listSources({})\nconst [source, ...refs] = sources\nconst { outputs } = await snaptrude.presentation.aiInspiration.generate({\nsourceShapeId: source.shapeId,\nprompt: \"Photorealistic render of a modern timber facade at dusk\",\nreferenceShapeIds: refs.slice(0, 2).map((r) => r.shapeId),\nreferenceStrength: \"medium\",\n})\nfor (const out of outputs ?? []) console.log(out.outputType, out.shapeId, out.outputUrl)\n```"
5470
6111
  ],
5471
6112
  "argsType": "PluginAIInspirationGenerateArgs",
5472
6113
  "resultType": "PluginAIInspirationRunResult"
5473
6114
  },
6115
+ {
6116
+ "path": "presentation.aiInspiration.getJob",
6117
+ "namespace": "presentation.aiInspiration",
6118
+ "summary": "Get a transient AI Inspiration job by ID.",
6119
+ "examplePrompts": [
6120
+ "Is my render finished?",
6121
+ "Check on the generation job\n\n# Example\n```ts\nconst { jobId } = await snaptrude.presentation.aiInspiration.generate({\nsourceShapeId: source.shapeId,\nprompt: \"Aerial dusk render\",\nrunMode: \"job\",\n})\nconst { job } = await snaptrude.presentation.aiInspiration.getJob({ jobId })\nconsole.log(job.status, job.progress?.message)\n```"
6122
+ ],
6123
+ "argsType": "PluginAIInspirationJobArgs",
6124
+ "resultType": "PluginAIInspirationGetJobResult"
6125
+ },
6126
+ {
6127
+ "path": "presentation.aiInspiration.getModelCapabilities",
6128
+ "namespace": "presentation.aiInspiration",
6129
+ "summary": "Get capability flags for a model.",
6130
+ "examplePrompts": [
6131
+ "What can this model do?",
6132
+ "Does the default model support reference images?",
6133
+ "Check if the video model supports keyframes\n\n# Example\n```ts\nconst { defaultModelId } = await snaptrude.presentation.aiInspiration.listModels()\nconst { capability } = await snaptrude.presentation.aiInspiration.getModelCapabilities({\nmodelId: defaultModelId,\n})\nconsole.log(capability.supportsReferenceImages, capability.maxExtraImages)\n```"
6134
+ ],
6135
+ "argsType": "PluginAIInspirationGetModelCapabilitiesArgs",
6136
+ "resultType": "PluginAIInspirationGetModelCapabilitiesResult"
6137
+ },
6138
+ {
6139
+ "path": "presentation.aiInspiration.getPresetCatalog",
6140
+ "namespace": "presentation.aiInspiration",
6141
+ "summary": "Get the curated AI Inspiration preset catalog.",
6142
+ "examplePrompts": [
6143
+ "What style presets are available?",
6144
+ "List the curated AI generation presets",
6145
+ "Show me the exterior render styles\n\n# Example\n```ts\nconst { categories, presets } = await snaptrude.presentation.aiInspiration.getPresetCatalog()\nconst exterior = presets.filter((p) => p.categoryLabel === \"Exterior\")\nconsole.log(categories.map((c) => c.label), exterior.map((p) => p.name))\n```"
6146
+ ],
6147
+ "argsType": null,
6148
+ "resultType": "PluginAIInspirationGetPresetCatalogResult"
6149
+ },
6150
+ {
6151
+ "path": "presentation.aiInspiration.getSelectedBranchRerunPlan",
6152
+ "namespace": "presentation.aiInspiration",
6153
+ "summary": "Build a rerun plan for the selected workflow branch ending at a shape.",
6154
+ "examplePrompts": [
6155
+ "Can I rerun the steps that produced this output?",
6156
+ "Preview the rerun for this generated image\n\n# Example\n```ts\nconst plan = await snaptrude.presentation.aiInspiration.getSelectedBranchRerunPlan({\nshapeId: selected.shapeId,\n})\nif (plan.status === \"ready\") console.log(plan.edges.map((e) => e.operation.label))\nelse console.log(\"Cannot rerun:\", plan.reason)\n```"
6157
+ ],
6158
+ "argsType": "PluginAIInspirationGetWorkflowForShapeArgs",
6159
+ "resultType": "PluginAIInspirationRerunPlanResult"
6160
+ },
6161
+ {
6162
+ "path": "presentation.aiInspiration.getSelection",
6163
+ "namespace": "presentation.aiInspiration",
6164
+ "summary": "Get selected Present canvas shapes that AI Inspiration can use.",
6165
+ "examplePrompts": [
6166
+ "Generate from what I have selected",
6167
+ "Which of my selected shapes can be used as AI sources?\n\n# Example\n```ts\nconst { selectedShapeIds, sources } = await snaptrude.presentation.aiInspiration.getSelection()\nconsole.log(selectedShapeIds.length, \"selected,\", sources.length, \"usable\")\n```"
6168
+ ],
6169
+ "argsType": null,
6170
+ "resultType": "PluginAIInspirationGetSelectionResult"
6171
+ },
6172
+ {
6173
+ "path": "presentation.aiInspiration.getWorkflowForShape",
6174
+ "namespace": "presentation.aiInspiration",
6175
+ "summary": "Get the sanitized workflow graph containing a Present shape.",
6176
+ "examplePrompts": [
6177
+ "Show the generation history of this image",
6178
+ "What workflow produced this shape?\n\n# Example\n```ts\nconst { workflow, node } = await snaptrude.presentation.aiInspiration.getWorkflowForShape({\nshapeId: selected.shapeId,\n})\nif (workflow && node) console.log(node.id, workflow.edgeIds.length, \"edges\")\n```"
6179
+ ],
6180
+ "argsType": "PluginAIInspirationGetWorkflowForShapeArgs",
6181
+ "resultType": "PluginAIInspirationGetWorkflowForShapeResult"
6182
+ },
6183
+ {
6184
+ "path": "presentation.aiInspiration.listJobs",
6185
+ "namespace": "presentation.aiInspiration",
6186
+ "summary": "List transient AI Inspiration jobs created in the current host session.",
6187
+ "examplePrompts": [
6188
+ "What AI jobs are running?",
6189
+ "Show my generation queue\n\n# Example\n```ts\nconst { jobs } = await snaptrude.presentation.aiInspiration.listJobs()\nconst running = jobs.filter((j) => j.status === \"running\" || j.status === \"queued\")\nconsole.log(running.map((j) => `${j.jobId}: ${j.method}`))\n```"
6190
+ ],
6191
+ "argsType": null,
6192
+ "resultType": "PluginAIInspirationListJobsResult"
6193
+ },
5474
6194
  {
5475
6195
  "path": "presentation.aiInspiration.listModels",
5476
6196
  "namespace": "presentation.aiInspiration",
@@ -5483,6 +6203,17 @@
5483
6203
  "argsType": null,
5484
6204
  "resultType": "PluginAIInspirationListModelsResult"
5485
6205
  },
6206
+ {
6207
+ "path": "presentation.aiInspiration.listRecipes",
6208
+ "namespace": "presentation.aiInspiration",
6209
+ "summary": "List project-level AI Inspiration recipes stored in Present document metadata.",
6210
+ "examplePrompts": [
6211
+ "What AI recipes are saved in this project?",
6212
+ "List my generation recipes\n\n# Example\n```ts\nconst { recipes } = await snaptrude.presentation.aiInspiration.listRecipes()\nconsole.log(recipes.map((r) => `${r.name} → ${r.outputKind}`))\n```"
6213
+ ],
6214
+ "argsType": null,
6215
+ "resultType": "PluginAIInspirationListRecipesResult"
6216
+ },
5486
6217
  {
5487
6218
  "path": "presentation.aiInspiration.listSources",
5488
6219
  "namespace": "presentation.aiInspiration",
@@ -5502,11 +6233,105 @@
5502
6233
  "examplePrompts": [
5503
6234
  "Upscale this AI image",
5504
6235
  "Refine and sharpen the selected render",
5505
- "Make this generated image higher resolution\n\n# Example\n```ts\nconst { sources } = await snaptrude.presentation.aiInspiration.listSources({ includeGenerated: true })\nconst image = sources.find((s) => s.kind === \"image\")\nif (image) {\nconst { outputs } = await snaptrude.presentation.aiInspiration.refine({\nsourceShapeId: image.shapeId,\nupscaleFactor: 2,\n})\nconsole.log(outputs[0].shapeId)\n}\n```"
6236
+ "Make this generated image higher resolution\n\n# Example\n```ts\nconst { sources } = await snaptrude.presentation.aiInspiration.listSources({ includeGenerated: true })\nconst image = sources.find((s) => s.kind === \"image\")\nif (image) {\nconst { outputs } = await snaptrude.presentation.aiInspiration.refine({\nsourceShapeId: image.shapeId,\nupscaleFactor: 2,\n})\nconsole.log(outputs?.[0]?.shapeId)\n}\n```"
5506
6237
  ],
5507
6238
  "argsType": "PluginAIInspirationRefineArgs",
5508
6239
  "resultType": "PluginAIInspirationRunResult"
5509
6240
  },
6241
+ {
6242
+ "path": "presentation.aiInspiration.rerunSelectedBranch",
6243
+ "namespace": "presentation.aiInspiration",
6244
+ "summary": "Rerun the selected workflow branch and supersede the previous branch.",
6245
+ "examplePrompts": [
6246
+ "Rerun this generation branch",
6247
+ "Regenerate this output with the same steps\n\n# Example\n```ts\nconst { outputs } = await snaptrude.presentation.aiInspiration.rerunSelectedBranch({\nshapeId: selected.shapeId,\n})\nconsole.log(outputs?.map((o) => o.shapeId))\n```"
6248
+ ],
6249
+ "argsType": "PluginAIInspirationRerunSelectedBranchArgs",
6250
+ "resultType": "PluginAIInspirationRunResult"
6251
+ },
6252
+ {
6253
+ "path": "presentation.aiInspiration.runRecipe",
6254
+ "namespace": "presentation.aiInspiration",
6255
+ "summary": "Run a saved or inline recipe against Present canvas slot shapes.",
6256
+ "examplePrompts": [
6257
+ "Apply my saved recipe to this image",
6258
+ "Run the dusk-render recipe on the selected view\n\n# Example\n```ts\nconst { recipes } = await snaptrude.presentation.aiInspiration.listRecipes()\nconst recipe = recipes[0]\nconst { sources } = await snaptrude.presentation.aiInspiration.listSources({})\nconst { outputs } = await snaptrude.presentation.aiInspiration.runRecipe({\nrecipeId: recipe.id,\nslotShapeIds: { [recipe.slots[0].id]: sources[0].shapeId },\n})\nconsole.log(outputs?.map((o) => o.outputUrl))\n```"
6259
+ ],
6260
+ "argsType": "PluginAIInspirationRunRecipeArgs",
6261
+ "resultType": "PluginAIInspirationRunResult"
6262
+ },
6263
+ {
6264
+ "path": "presentation.aiInspiration.saveRecipe",
6265
+ "namespace": "presentation.aiInspiration",
6266
+ "summary": "Save a project-level AI Inspiration recipe.",
6267
+ "examplePrompts": [
6268
+ "Save this recipe as \"Dusk facade render\"",
6269
+ "Store these generation steps for reuse\n\n# Example\n```ts\nconst extraction = await snaptrude.presentation.aiInspiration.extractRecipeFromShape({\nshapeId: selected.shapeId,\n})\nif (extraction.status === \"ready\") {\nconst saved = await snaptrude.presentation.aiInspiration.saveRecipe({\ndraft: extraction.draft,\nname: \"Dusk facade render\",\n})\nconsole.log(saved.status, saved.recipe?.id)\n}\n```"
6270
+ ],
6271
+ "argsType": "PluginAIInspirationSaveRecipeArgs",
6272
+ "resultType": "PluginAIInspirationSaveRecipeResult"
6273
+ },
6274
+ {
6275
+ "path": "presentation.annotate.arrow",
6276
+ "namespace": "presentation.annotate",
6277
+ "summary": "Draw an arrow on a sheet.",
6278
+ "examplePrompts": [
6279
+ "Draw an arrow pointing at the entrance on Sheet 1",
6280
+ "Add a red arrow from the title to the plan view",
6281
+ "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```"
6282
+ ],
6283
+ "argsType": "string",
6284
+ "resultType": "PluginPresentationAnnotateResult"
6285
+ },
6286
+ {
6287
+ "path": "presentation.annotate.note",
6288
+ "namespace": "presentation.annotate",
6289
+ "summary": "Add a sticky note to a sheet.",
6290
+ "examplePrompts": [
6291
+ "Add a sticky note \"Review this wall\" to Sheet 1",
6292
+ "Put a yellow note on the cover sheet",
6293
+ "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```"
6294
+ ],
6295
+ "argsType": "string",
6296
+ "resultType": "PluginPresentationAnnotateResult"
6297
+ },
6298
+ {
6299
+ "path": "presentation.annotate.shape",
6300
+ "namespace": "presentation.annotate",
6301
+ "summary": "Draw a geo shape (rectangle, ellipse, cloud, …) on a sheet.",
6302
+ "examplePrompts": [
6303
+ "Draw a revision cloud around the kitchen on Sheet 2",
6304
+ "Add a red rectangle highlight to the sheet",
6305
+ "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```"
6306
+ ],
6307
+ "argsType": "string",
6308
+ "resultType": "PluginPresentationAnnotateResult"
6309
+ },
6310
+ {
6311
+ "path": "presentation.annotate.text",
6312
+ "namespace": "presentation.annotate",
6313
+ "summary": "Add a text label to a sheet.",
6314
+ "examplePrompts": [
6315
+ "Add a title \"Ground Floor\" to Sheet 1",
6316
+ "Label the cover sheet with the project name",
6317
+ "Caption this view with \"Proposed layout\"",
6318
+ "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```"
6319
+ ],
6320
+ "argsType": "string",
6321
+ "resultType": "PluginPresentationAnnotateTextResult"
6322
+ },
6323
+ {
6324
+ "path": "presentation.diagrams.generateProgram",
6325
+ "namespace": "presentation.diagrams",
6326
+ "summary": "Generate the program (space + department) diagrams for the current model, creating new layout sheets.",
6327
+ "examplePrompts": [
6328
+ "Generate the program diagrams for this project",
6329
+ "Auto-generate the space and department diagram sheets",
6330
+ "Create the program layout sheets from the model\n\n# Example\n```ts\nconst { sheetIds } = await snaptrude.presentation.diagrams.generateProgram()\n```"
6331
+ ],
6332
+ "argsType": null,
6333
+ "resultType": "PluginPresentationDiagramsGenerateResult"
6334
+ },
5510
6335
  {
5511
6336
  "path": "presentation.diagrams.place",
5512
6337
  "namespace": "presentation.diagrams",
@@ -5572,18 +6397,153 @@
5572
6397
  "argsType": "{ url?: string; dataUrl?: string }",
5573
6398
  "resultType": "PluginPresentationImportResult"
5574
6399
  },
6400
+ {
6401
+ "path": "presentation.placedViews.get",
6402
+ "namespace": "presentation.placedViews",
6403
+ "summary": "Get a single placed view by its shape id.",
6404
+ "examplePrompts": [
6405
+ "Get the placed view I just dropped on the sheet",
6406
+ "Read the position and scale of this placed view",
6407
+ "What's the crop on shape_123?\n\n# Example\n```ts\nconst placed = await snaptrude.presentation.placedViews.get(shapeId)\nconsole.log(placed.position, placed.scale)\n```"
6408
+ ],
6409
+ "argsType": "string",
6410
+ "resultType": "PluginPlacedView"
6411
+ },
6412
+ {
6413
+ "path": "presentation.placedViews.list",
6414
+ "namespace": "presentation.placedViews",
6415
+ "summary": "List the placed views in the presentation.",
6416
+ "examplePrompts": [
6417
+ "Which views are placed on this sheet?",
6418
+ "List all the placed views in the presentation",
6419
+ "What's laid out on sheet 2?",
6420
+ "Show me every view on the Present canvas\n\n# Example\n```ts\nconst { placedViews } = await snaptrude.presentation.placedViews.list(\"sheet_1\")\n```"
6421
+ ],
6422
+ "argsType": "string",
6423
+ "resultType": "PluginPresentationPlacedViewsListResult"
6424
+ },
6425
+ {
6426
+ "path": "presentation.placedViews.move",
6427
+ "namespace": "presentation.placedViews",
6428
+ "summary": "Move a placed view.",
6429
+ "examplePrompts": [
6430
+ "Move the site plan view to the top-left of sheet 2",
6431
+ "Reposition this placed view to 100, 200",
6432
+ "Move the hero perspective onto the cover sheet\n\n# Example\n```ts\nawait snaptrude.presentation.placedViews.move(shapeId, { x: 50, y: 50 }, {\nsheetId: \"sheet_2\",\n})\n```"
6433
+ ],
6434
+ "argsType": "string",
6435
+ "resultType": "PluginPlacedView"
6436
+ },
6437
+ {
6438
+ "path": "presentation.placedViews.scale",
6439
+ "namespace": "presentation.placedViews",
6440
+ "summary": "Resize a placed view by a uniform factor.",
6441
+ "examplePrompts": [
6442
+ "Make this placed view twice as big",
6443
+ "Shrink the placed 3D view to half its size",
6444
+ "Scale the placed plan up by 50%\n\n# Example\n```ts\nawait snaptrude.presentation.placedViews.scale(shapeId, 2)\n```"
6445
+ ],
6446
+ "argsType": "string",
6447
+ "resultType": "PluginPlacedView"
6448
+ },
6449
+ {
6450
+ "path": "presentation.placedViews.setCrop",
6451
+ "namespace": "presentation.placedViews",
6452
+ "summary": "Crop a placed view, or clear its crop.",
6453
+ "examplePrompts": [
6454
+ "Crop the placed view to its left half",
6455
+ "Crop this view to the top-right quarter",
6456
+ "Remove the crop from the placed plan\n\n# Example\n```ts\n// keep the left half of the view\nawait snaptrude.presentation.placedViews.setCrop(shapeId, {\ntopLeft: { x: 0, y: 0 },\nbottomRight: { x: 0.5, y: 1 },\n})\nawait snaptrude.presentation.placedViews.setCrop(shapeId, null) // clear\n```"
6457
+ ],
6458
+ "argsType": "string",
6459
+ "resultType": "PluginPlacedView"
6460
+ },
6461
+ {
6462
+ "path": "presentation.placedViews.setScale",
6463
+ "namespace": "presentation.placedViews",
6464
+ "summary": "Set a placed view's architectural scale.",
6465
+ "examplePrompts": [
6466
+ "Set the plan to 1:100",
6467
+ "Change the placed floor plan to 1:50 scale",
6468
+ "Make this view print at quarter-inch scale\n\n# Example\n```ts\nawait snaptrude.presentation.placedViews.setScale(shapeId, 100) // 1:100\n```"
6469
+ ],
6470
+ "argsType": "string",
6471
+ "resultType": "PluginPlacedView"
6472
+ },
6473
+ {
6474
+ "path": "presentation.shapes.list",
6475
+ "namespace": "presentation.shapes",
6476
+ "summary": "List the calling plugin's shapes.",
6477
+ "examplePrompts": [
6478
+ "Which annotations has my plugin placed on the sheets?",
6479
+ "List the plugin's shapes before refreshing them",
6480
+ "Check whether the FAR label already exists\n\n# Example\n```ts\nconst { shapes } = await snaptrude.presentation.shapes.list()\nconst hasLabel = shapes.some((s) => s.key === \"far-label\")\n```"
6481
+ ],
6482
+ "argsType": null,
6483
+ "resultType": "PluginPresentationShapesListResult"
6484
+ },
6485
+ {
6486
+ "path": "presentation.shapes.remove",
6487
+ "namespace": "presentation.shapes",
6488
+ "summary": "Delete the shape for a key.",
6489
+ "examplePrompts": [
6490
+ "Remove the FAR label from the sheet",
6491
+ "Delete the highlight the plugin added earlier",
6492
+ "Clear the \"far-label\" annotation\n\n# Example\n```ts\nconst removed = await snaptrude.presentation.shapes.remove(\"far-label\")\n```"
6493
+ ],
6494
+ "argsType": "string",
6495
+ "resultType": "boolean"
6496
+ },
6497
+ {
6498
+ "path": "presentation.shapes.removeAll",
6499
+ "namespace": "presentation.shapes",
6500
+ "summary": "Delete every shape owned by the calling plugin.",
6501
+ "examplePrompts": [
6502
+ "Clear all annotations my plugin added",
6503
+ "Reset the sheet output before rerunning the analysis",
6504
+ "Remove every plugin-drawn shape\n\n# Example\n```ts\nconst deleted = await snaptrude.presentation.shapes.removeAll()\n```"
6505
+ ],
6506
+ "argsType": null,
6507
+ "resultType": "number"
6508
+ },
6509
+ {
6510
+ "path": "presentation.shapes.upsert",
6511
+ "namespace": "presentation.shapes",
6512
+ "summary": "Create or update the shape for a key.",
6513
+ "examplePrompts": [
6514
+ "Update the analysis label on the sheet instead of adding another one",
6515
+ "Rerun the daylight report and refresh its annotations",
6516
+ "Keep one \"FAR: 2.4\" text on Sheet 1 that updates on each run",
6517
+ "Draw a highlight rectangle the plugin can move on the next run\n\n# Example\n```ts\nconst { shapeId, created } = await snaptrude.presentation.shapes.upsert(\"far-label\", {\ntype: \"text\",\ntext: \"FAR: 2.4\",\nposition: { x: 40, y: 40 },\ncolor: \"blue\",\n})\n```"
6518
+ ],
6519
+ "argsType": "string",
6520
+ "resultType": "PluginPresentationShapesUpsertResult"
6521
+ },
5575
6522
  {
5576
6523
  "path": "presentation.sheets.create",
5577
6524
  "namespace": "presentation.sheets",
5578
6525
  "summary": "Create a new layout sheet.",
5579
6526
  "examplePrompts": [
5580
6527
  "Create a new sheet called Cover",
5581
- "Add a layout sheet",
5582
- "Make a new presentation sheet named Floor Plans\n\n# Example\n```ts\nconst sheet = await snaptrude.presentation.sheets.create(\"Cover\")\n```"
6528
+ "Add an A3 landscape layout sheet",
6529
+ "Make a new ANSI D presentation sheet named Floor Plans",
6530
+ "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```"
5583
6531
  ],
5584
6532
  "argsType": "string",
5585
6533
  "resultType": "PluginPresentationSheet"
5586
6534
  },
6535
+ {
6536
+ "path": "presentation.sheets.delete",
6537
+ "namespace": "presentation.sheets",
6538
+ "summary": "Delete a layout sheet.",
6539
+ "examplePrompts": [
6540
+ "Delete sheet_2",
6541
+ "Remove the Cover sheet",
6542
+ "Get rid of the last layout sheet\n\n# Example\n```ts\nconst { id } = await snaptrude.presentation.sheets.delete(\"sheet_2\")\n```"
6543
+ ],
6544
+ "argsType": "string",
6545
+ "resultType": "PluginPresentationSheetsDeleteResult"
6546
+ },
5587
6547
  {
5588
6548
  "path": "presentation.sheets.get",
5589
6549
  "namespace": "presentation.sheets",
@@ -5617,11 +6577,73 @@
5617
6577
  "Place the floor plan on Sheet 1",
5618
6578
  "Add this 3D view to the cover sheet",
5619
6579
  "Drop the site plan onto the layout sheet at 100, 200",
5620
- "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```"
6580
+ "Put the Ground Floor view on sheet_1 at 1:100 scale",
6581
+ "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```"
5621
6582
  ],
5622
6583
  "argsType": "string",
5623
6584
  "resultType": "PluginPresentationSheetsPlaceResult"
5624
6585
  },
6586
+ {
6587
+ "path": "presentation.sheets.rename",
6588
+ "namespace": "presentation.sheets",
6589
+ "summary": "Rename a layout sheet.",
6590
+ "examplePrompts": [
6591
+ "Rename sheet_1 to Cover",
6592
+ "Call the first sheet Ground Floor",
6593
+ "Change this sheet's name to Site Plan\n\n# Example\n```ts\nconst sheet = await snaptrude.presentation.sheets.rename(\"sheet_1\", \"Cover\")\n```"
6594
+ ],
6595
+ "argsType": "string",
6596
+ "resultType": "PluginPresentationSheet"
6597
+ },
6598
+ {
6599
+ "path": "presentation.sheets.reorder",
6600
+ "namespace": "presentation.sheets",
6601
+ "summary": "Move a sheet to a new position in the sheet order.",
6602
+ "examplePrompts": [
6603
+ "Move sheet_3 to the front",
6604
+ "Make the Cover sheet the first sheet",
6605
+ "Reorder this sheet to position 2\n\n# Example\n```ts\nconst { sheets } = await snaptrude.presentation.sheets.reorder(\"sheet_3\", 0)\n```"
6606
+ ],
6607
+ "argsType": "string",
6608
+ "resultType": "PluginPresentationSheetsListResult"
6609
+ },
6610
+ {
6611
+ "path": "presentation.sheets.setActive",
6612
+ "namespace": "presentation.sheets",
6613
+ "summary": "Make a sheet the active sheet.",
6614
+ "examplePrompts": [
6615
+ "Go to sheet_1",
6616
+ "Open the Cover sheet",
6617
+ "Switch to the Site Plan sheet\n\n# Example\n```ts\nawait snaptrude.presentation.sheets.setActive(\"sheet_1\")\n```"
6618
+ ],
6619
+ "argsType": "string",
6620
+ "resultType": "PluginPresentationSheet"
6621
+ },
6622
+ {
6623
+ "path": "presentation.sheets.setSize",
6624
+ "namespace": "presentation.sheets",
6625
+ "summary": "Set a sheet's paper size and/or orientation.",
6626
+ "examplePrompts": [
6627
+ "Resize sheet_1 to A1",
6628
+ "Make the cover sheet ANSI B portrait",
6629
+ "Change this sheet to Arch D landscape",
6630
+ "Set the sheet size to A3\n\n# Example\n```ts\nconst sheet = await snaptrude.presentation.sheets.setSize(\"sheet_1\", \"ISO_A1\", \"portrait\")\n```"
6631
+ ],
6632
+ "argsType": "string",
6633
+ "resultType": "PluginPresentationSheet"
6634
+ },
6635
+ {
6636
+ "path": "presentation.sheets.updatePlacedView",
6637
+ "namespace": "presentation.sheets",
6638
+ "summary": "Refresh placed views to the current model state.",
6639
+ "examplePrompts": [
6640
+ "Update all the placed views to the latest model",
6641
+ "Refresh the views on sheet_1",
6642
+ "Re-render the placed views after my edits\n\n# Example\n```ts\nconst { shapeIds } = await snaptrude.presentation.sheets.updatePlacedView()\n```"
6643
+ ],
6644
+ "argsType": "{\n sheetId?: string\n }",
6645
+ "resultType": "PluginPresentationSheetsUpdatePlacedViewResult"
6646
+ },
5625
6647
  {
5626
6648
  "path": "presentation.views.capture",
5627
6649
  "namespace": "presentation.views",
@@ -5643,11 +6665,24 @@
5643
6665
  "Save the current view as Lobby Perspective",
5644
6666
  "Create a new saved view from where I'm looking",
5645
6667
  "Bookmark this camera angle",
5646
- "Save the current 2D plan as a view\n\n# Example\n```ts\nconst view = await snaptrude.presentation.views.create(\"Lobby\")\n```"
6668
+ "Save the current 2D plan as a view",
6669
+ "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```"
5647
6670
  ],
5648
6671
  "argsType": "string",
5649
6672
  "resultType": "PluginPresentationViewsCreateResult"
5650
6673
  },
6674
+ {
6675
+ "path": "presentation.views.delete",
6676
+ "namespace": "presentation.views",
6677
+ "summary": "Delete a saved view.",
6678
+ "examplePrompts": [
6679
+ "Delete the view named Old Draft",
6680
+ "Remove this saved view",
6681
+ "Get rid of the Lobby camera bookmark\n\n# Example\n```ts\nconst { id } = await snaptrude.presentation.views.delete(\"view_123\")\n```"
6682
+ ],
6683
+ "argsType": "string",
6684
+ "resultType": "PluginPresentationViewsDeleteResult"
6685
+ },
5651
6686
  {
5652
6687
  "path": "presentation.views.get",
5653
6688
  "namespace": "presentation.views",
@@ -5675,7 +6710,7 @@
5675
6710
  {
5676
6711
  "path": "presentation.views.getSettings",
5677
6712
  "namespace": "presentation.views",
5678
- "summary": "Read a saved view's display settings (background, color mode, axis, edges, labels).",
6713
+ "summary": "Read a saved view's display settings (background, color mode, view mode, axis, edges, labels).",
5679
6714
  "examplePrompts": [
5680
6715
  "What color mode is the Ground Floor view using?",
5681
6716
  "Get the display settings for this view",
@@ -5699,6 +6734,18 @@
5699
6734
  "argsType": null,
5700
6735
  "resultType": "PluginPresentationViewsListResult"
5701
6736
  },
6737
+ {
6738
+ "path": "presentation.views.rename",
6739
+ "namespace": "presentation.views",
6740
+ "summary": "Rename a saved view.",
6741
+ "examplePrompts": [
6742
+ "Rename the view Lobby to Entrance Lobby",
6743
+ "Call this view Ground Floor Plan",
6744
+ "Change the active view's name to Final\n\n# Example\n```ts\nconst view = await snaptrude.presentation.views.rename(\"view_123\", \"Entrance\")\n```"
6745
+ ],
6746
+ "argsType": "string",
6747
+ "resultType": "PluginPresentationViewsRenameResult"
6748
+ },
5702
6749
  {
5703
6750
  "path": "presentation.views.setActive",
5704
6751
  "namespace": "presentation.views",
@@ -5721,7 +6768,8 @@
5721
6768
  "Turn off the axis in the Ground Floor view",
5722
6769
  "Set the background of the active view to white",
5723
6770
  "Show area labels on this view",
5724
- "Enable hidden-line mode for the section view\n\n# Example\n```ts\nawait snaptrude.presentation.views.updateSettings(\"view_123\", {\ncolorMode: \"monochrome\",\nshowAxis: false,\n})\n```"
6771
+ "Enable hidden-line mode for the section view",
6772
+ "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```"
5725
6773
  ],
5726
6774
  "argsType": "string",
5727
6775
  "resultType": "PluginPresentationViewsUpdateSettingsResult"
@@ -5793,6 +6841,18 @@
5793
6841
  "argsType": "PluginProgramAreaGroupBy",
5794
6842
  "resultType": "PluginProgramAreasListMembersResult"
5795
6843
  },
6844
+ {
6845
+ "path": "program.areas.refresh",
6846
+ "namespace": "program.areas",
6847
+ "summary": "Force the area breakdown to recompute, then return the fresh summary.",
6848
+ "examplePrompts": [
6849
+ "Recompute the area totals before I read them",
6850
+ "Refresh the FAR numbers",
6851
+ "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```"
6852
+ ],
6853
+ "argsType": null,
6854
+ "resultType": "PluginProgramAreasRefreshResult"
6855
+ },
5796
6856
  {
5797
6857
  "path": "program.areas.update",
5798
6858
  "namespace": "program.areas",
@@ -5802,7 +6862,7 @@
5802
6862
  "Override the site area to 5000",
5803
6863
  "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```"
5804
6864
  ],
5805
- "argsType": "{ targetFar?: number; siteArea?: number; deviation?: number }",
6865
+ "argsType": "{\n targetFar?: number\n siteArea?: number\n deviation?: number\n }",
5806
6866
  "resultType": "PluginProgramAreasUpdateResult"
5807
6867
  },
5808
6868
  {
@@ -5959,6 +7019,18 @@
5959
7019
  "argsType": "string",
5960
7020
  "resultType": "PluginProgramDepartmentsUpdateResult"
5961
7021
  },
7022
+ {
7023
+ "path": "program.layout.applySolution",
7024
+ "namespace": "program.layout",
7025
+ "summary": "Apply one of the pending arrange solutions.",
7026
+ "examplePrompts": [
7027
+ "Apply the second arrange solution",
7028
+ "Pick layout solution 3 and commit it",
7029
+ "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```"
7030
+ ],
7031
+ "argsType": "number",
7032
+ "resultType": "PluginProgramLayoutApplyResult"
7033
+ },
5962
7034
  {
5963
7035
  "path": "program.layout.arrange",
5964
7036
  "namespace": "program.layout",
@@ -5966,7 +7038,8 @@
5966
7038
  "examplePrompts": [
5967
7039
  "Arrange the rooms in the envelope",
5968
7040
  "Lay out the departments inside the building envelope",
5969
- "Auto-arrange the program spaces\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```"
7041
+ "Auto-arrange the program spaces",
7042
+ "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```"
5970
7043
  ],
5971
7044
  "argsType": "PluginProgramLayoutRunArgs",
5972
7045
  "resultType": "PluginProgramLayoutRunResult"
@@ -6007,6 +7080,18 @@
6007
7080
  "argsType": "PluginProgramLayoutRunArgs",
6008
7081
  "resultType": "PluginProgramLayoutRunResult"
6009
7082
  },
7083
+ {
7084
+ "path": "program.layout.stack",
7085
+ "namespace": "program.layout",
7086
+ "summary": "Stack the program across **every storey** of the building — the product's *Pack in envelope* / auto-stack.",
7087
+ "examplePrompts": [
7088
+ "Stack the program across all floors",
7089
+ "Auto-stack the departments into the envelope on every storey",
7090
+ "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```"
7091
+ ],
7092
+ "argsType": null,
7093
+ "resultType": "PluginProgramLayoutStackResult"
7094
+ },
6010
7095
  {
6011
7096
  "path": "program.metrics.get",
6012
7097
  "namespace": "program.metrics",
@@ -6085,6 +7170,31 @@
6085
7170
  "argsType": null,
6086
7171
  "resultType": "PluginProgramSiteNorthAngleResult"
6087
7172
  },
7173
+ {
7174
+ "path": "program.site.getTimezone",
7175
+ "namespace": "program.site",
7176
+ "summary": "Get the IANA timezone of the project's geographic location.",
7177
+ "examplePrompts": [
7178
+ "What timezone is this project in?",
7179
+ "Get the site's IANA timezone",
7180
+ "What's the local time zone at the project location?",
7181
+ "Which timezone should I use for the sun study schedule?\n\n# Example\n```ts\nconst timezone = await snaptrude.program.site.getTimezone()\nif (timezone) console.log(`Project timezone: ${timezone}`)\n```"
7182
+ ],
7183
+ "argsType": null,
7184
+ "resultType": "PluginProgramSiteTimezoneResult"
7185
+ },
7186
+ {
7187
+ "path": "program.site.getWeather",
7188
+ "namespace": "program.site",
7189
+ "summary": "Get the weather file resolved for the project site.",
7190
+ "examplePrompts": [
7191
+ "Which weather file is my project using?",
7192
+ "What EPW station was resolved for this site?",
7193
+ "Get the weather file id for the daylight analysis\n\n# Example\n```ts\nconst weather = await snaptrude.program.site.getWeather()\nif (weather) console.log(weather.station, weather.selectionMethod)\n```"
7194
+ ],
7195
+ "argsType": null,
7196
+ "resultType": "PluginProgramSiteWeatherResult"
7197
+ },
6088
7198
  {
6089
7199
  "path": "program.site.listGeoPolygons",
6090
7200
  "namespace": "program.site",
@@ -6101,7 +7211,7 @@
6101
7211
  {
6102
7212
  "path": "program.site.listPolygons",
6103
7213
  "namespace": "program.site",
6104
- "summary": "List the site parcels with their footprints (in scene coordinates).",
7214
+ "summary": "List the site parcels with their footprints (world XZ plan coordinates, Snaptrude units).",
6105
7215
  "examplePrompts": [
6106
7216
  "List every site parcel",
6107
7217
  "Show me each plot's footprint",
@@ -6136,6 +7246,19 @@
6136
7246
  "argsType": "string",
6137
7247
  "resultType": "PluginProgramSpreadsheetAddConditionalFormattingResult"
6138
7248
  },
7249
+ {
7250
+ "path": "program.spreadsheet.addImage",
7251
+ "namespace": "program.spreadsheet",
7252
+ "summary": "Place a floating image on a workbook sheet from a base64 data URI.",
7253
+ "examplePrompts": [
7254
+ "Add my logo image to the report sheet",
7255
+ "Place a PNG at cell B2 on the Takeoff sheet",
7256
+ "Put an SVG diagram on a spreadsheet sheet",
7257
+ "Insert an image into the workbook\n\n# Example\n```ts\nconst { name } = await snaptrude.program.spreadsheet.addImage(\n\"Report\",\n{ dataUri: \"data:image/png;base64,iVBORw0...\" },\n{ anchorCell: \"B2\", size: { width: 240, height: 120 }, name: \"logo\" },\n)\n```"
7258
+ ],
7259
+ "argsType": "string",
7260
+ "resultType": "PluginProgramSpreadsheetAddImageResult"
7261
+ },
6139
7262
  {
6140
7263
  "path": "program.spreadsheet.bindings.create",
6141
7264
  "namespace": "program.spreadsheet.bindings",
@@ -6169,7 +7292,7 @@
6169
7292
  "Re-pull all my data bindings",
6170
7293
  "Refresh every binding on the sheets\n\n# Example\n```ts\nawait snaptrude.program.spreadsheet.bindings.refresh({ name: \"takeoff\" })\n```"
6171
7294
  ],
6172
- "argsType": "{ name?: string }",
7295
+ "argsType": "{\n name?: string\n }",
6173
7296
  "resultType": "PluginProgramSpreadsheetBindingsRefreshResult"
6174
7297
  },
6175
7298
  {
@@ -6185,15 +7308,41 @@
6185
7308
  "argsType": "string",
6186
7309
  "resultType": "PluginProgramSpreadsheetCreateSheetResult"
6187
7310
  },
7311
+ {
7312
+ "path": "program.spreadsheet.datasets.list",
7313
+ "namespace": "program.spreadsheet.datasets",
7314
+ "summary": "List the stored plugin datasets.",
7315
+ "examplePrompts": [
7316
+ "List my plugin datasets",
7317
+ "What datasets are stored for the sheets?",
7318
+ "Show the data sets bindings can use\n\n# Example\n```ts\nconst { datasets } = await snaptrude.program.spreadsheet.datasets.list()\n```"
7319
+ ],
7320
+ "argsType": null,
7321
+ "resultType": "PluginProgramSpreadsheetDatasetsListResult"
7322
+ },
7323
+ {
7324
+ "path": "program.spreadsheet.datasets.set",
7325
+ "namespace": "program.spreadsheet.datasets",
7326
+ "summary": "Store (upsert) a named plugin dataset.",
7327
+ "examplePrompts": [
7328
+ "Store my plugin's rows as a named dataset",
7329
+ "Upload data the sheets can bind to and refresh",
7330
+ "Save a dataset for a live sheet binding",
7331
+ "Push my computed table so a binding keeps it fresh\n\n# Example\n```ts\nawait snaptrude.program.spreadsheet.datasets.set(\n\"costs\",\n[\n{ key: \"item\", header: \"Item\" },\n{ key: \"cost\", header: \"Cost\", align: \"right\" },\n],\n[{ item: \"Concrete\", cost: 120 }],\n)\n```"
7332
+ ],
7333
+ "argsType": "string",
7334
+ "resultType": "PluginProgramSpreadsheetDatasetsSetResult"
7335
+ },
6188
7336
  {
6189
7337
  "path": "program.spreadsheet.export",
6190
7338
  "namespace": "program.spreadsheet",
6191
- "summary": "Export the whole report workbook to a file (xlsx, pdf, or csv).",
7339
+ "summary": "Export the report workbook to a file (xlsx, pdf, or csv).",
6192
7340
  "examplePrompts": [
6193
7341
  "Export the report as an Excel file",
6194
7342
  "Download the whole workbook as a PDF",
6195
7343
  "Export the program workbook to xlsx",
6196
- "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```"
7344
+ "Save the report as a csv file",
7345
+ "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```"
6197
7346
  ],
6198
7347
  "argsType": "PluginSpreadsheetExportFormat",
6199
7348
  "resultType": "PluginProgramSpreadsheetExportResult"
@@ -6208,9 +7357,23 @@
6208
7357
  "Get the last 10 audit log entries",
6209
7358
  "Read the program spreadsheet audit log\n\n# Example\n```ts\nconst { entries } = await snaptrude.program.spreadsheet.getAuditLog({ limit: 10 })\n```"
6210
7359
  ],
6211
- "argsType": "{ limit?: number }",
7360
+ "argsType": "{\n limit?: number\n }",
6212
7361
  "resultType": "PluginProgramSpreadsheetGetAuditLogResult"
6213
7362
  },
7363
+ {
7364
+ "path": "program.spreadsheet.getMaterialTakeoff",
7365
+ "namespace": "program.spreadsheet",
7366
+ "summary": "Read the material take-off dataset (surface area per material, per element type).",
7367
+ "examplePrompts": [
7368
+ "Get the material take-off",
7369
+ "How much of each material is used?",
7370
+ "Read the surface area by material",
7371
+ "Give me the material quantities before I render them",
7372
+ "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```"
7373
+ ],
7374
+ "argsType": null,
7375
+ "resultType": "PluginProgramSpreadsheetGetMaterialTakeoffResult"
7376
+ },
6214
7377
  {
6215
7378
  "path": "program.spreadsheet.getProgram",
6216
7379
  "namespace": "program.spreadsheet",
@@ -6309,7 +7472,7 @@
6309
7472
  "Recompute all the formulas",
6310
7473
  "Recalculate the Summary sheet\n\n# Example\n```ts\nawait snaptrude.program.spreadsheet.recalculate()\n```"
6311
7474
  ],
6312
- "argsType": "{ sheetName?: string }",
7475
+ "argsType": "{\n sheetName?: string\n }",
6313
7476
  "resultType": "PluginProgramSpreadsheetRecalculateResult"
6314
7477
  },
6315
7478
  {
@@ -6336,7 +7499,7 @@
6336
7499
  "Generate the program schedule sheet titled Program",
6337
7500
  "Render the program filtered to the residential departments\n\n# Example\n```ts\nawait snaptrude.program.spreadsheet.renderProgram({ sheetName: \"Program\" })\n```"
6338
7501
  ],
6339
- "argsType": "{ sheetName?: string; title?: string; filter?: string }",
7502
+ "argsType": "{\n sheetName?: string\n title?: string\n filter?: string\n }",
6340
7503
  "resultType": "PluginProgramSpreadsheetRenderResult"
6341
7504
  },
6342
7505
  {
@@ -6349,7 +7512,7 @@
6349
7512
  "Generate the takeoff schedule sheet titled Takeoff",
6350
7513
  "Render the material takeoff filtered to the walls\n\n# Example\n```ts\nawait snaptrude.program.spreadsheet.renderTakeoff({ sheetName: \"Takeoff\" })\n```"
6351
7514
  ],
6352
- "argsType": "{ sheetName?: string; title?: string; filter?: string }",
7515
+ "argsType": "{\n sheetName?: string\n title?: string\n filter?: string\n }",
6353
7516
  "resultType": "PluginProgramSpreadsheetRenderResult"
6354
7517
  },
6355
7518
  {
@@ -6438,5 +7601,103 @@
6438
7601
  ],
6439
7602
  "argsType": "PluginSpreadsheetTransactionOp[]",
6440
7603
  "resultType": "PluginProgramSpreadsheetTransactionResult"
7604
+ },
7605
+ {
7606
+ "path": "workspace.projects.copy",
7607
+ "namespace": "workspace.projects",
7608
+ "summary": "Copy the **current** project into a new project — the dashboard's \"Save As\".",
7609
+ "examplePrompts": [
7610
+ "Save this project as a new copy called Tower Study v2",
7611
+ "Duplicate the current project into the Acme team",
7612
+ "Make a copy of this project so I can try changes\n\n# Example\n```ts\nconst { projectId } = await snaptrude.workspace.projects.copy(\"Tower Study v2\")\n```"
7613
+ ],
7614
+ "argsType": "string",
7615
+ "resultType": "PluginWorkspaceProjectsCopyResult"
7616
+ },
7617
+ {
7618
+ "path": "workspace.projects.create",
7619
+ "namespace": "workspace.projects",
7620
+ "summary": "Create a new, empty BIM project.",
7621
+ "examplePrompts": [
7622
+ "Create a new project called Tower Study",
7623
+ "Start a new project in the Acme team",
7624
+ "Make a fresh project using millimeters",
7625
+ "Create an empty project for me to work in\n\n# Example\n```ts\nconst { projectId } = await snaptrude.workspace.projects.create(\"Tower Study\", {\nteamId: \"team_1\",\nunit: \"mm\",\n})\n```"
7626
+ ],
7627
+ "argsType": "string",
7628
+ "resultType": "PluginWorkspaceProjectsCreateResult"
7629
+ },
7630
+ {
7631
+ "path": "workspace.projects.get",
7632
+ "namespace": "workspace.projects",
7633
+ "summary": "Get a single project by id.",
7634
+ "examplePrompts": [
7635
+ "Get the project with this id",
7636
+ "Look up a project by its floorkey",
7637
+ "What is the name of this project?\n\n# Example\n```ts\nconst project = await snaptrude.workspace.projects.get(\"floorkey_123\")\nif (project) console.log(project.name)\n```"
7638
+ ],
7639
+ "argsType": "string",
7640
+ "resultType": "PluginWorkspaceProjectsGetResult"
7641
+ },
7642
+ {
7643
+ "path": "workspace.projects.list",
7644
+ "namespace": "workspace.projects",
7645
+ "summary": "List the projects the user can access.",
7646
+ "examplePrompts": [
7647
+ "List all my projects",
7648
+ "Show the projects in the Acme team",
7649
+ "How many projects do I have?",
7650
+ "What projects can I open?\n\n# Example\n```ts\nconst { projects } = await snaptrude.workspace.projects.list({ teamId: \"team_1\" })\nfor (const p of projects) console.log(p.id, p.name)\n```"
7651
+ ],
7652
+ "argsType": "{ teamId?: string }",
7653
+ "resultType": "PluginWorkspaceProjectsListResult"
7654
+ },
7655
+ {
7656
+ "path": "workspace.projects.rename",
7657
+ "namespace": "workspace.projects",
7658
+ "summary": "Rename a project.",
7659
+ "examplePrompts": [
7660
+ "Rename this project to Tower Study Final",
7661
+ "Change the name of project floorkey_123",
7662
+ "Give this project a new name\n\n# Example\n```ts\nconst { projectId } = await snaptrude.workspace.projects.rename(\n\"floorkey_123\",\n\"Tower Study Final\",\n)\n```"
7663
+ ],
7664
+ "argsType": "string",
7665
+ "resultType": "PluginWorkspaceProjectsRenameResult"
7666
+ },
7667
+ {
7668
+ "path": "workspace.teams.get",
7669
+ "namespace": "workspace.teams",
7670
+ "summary": "Get a single team by id.",
7671
+ "examplePrompts": [
7672
+ "Get the team with id team_1",
7673
+ "Look up a team by its id",
7674
+ "What is the name of this team?\n\n# Example\n```ts\nconst team = await snaptrude.workspace.teams.get(\"team_1\")\nif (team) console.log(team.name)\n```"
7675
+ ],
7676
+ "argsType": "string",
7677
+ "resultType": "PluginWorkspaceTeamsGetResult"
7678
+ },
7679
+ {
7680
+ "path": "workspace.teams.list",
7681
+ "namespace": "workspace.teams",
7682
+ "summary": "List the teams the user belongs to.",
7683
+ "examplePrompts": [
7684
+ "List all my teams",
7685
+ "Which teams am I a member of?",
7686
+ "Show every team I can access\n\n# Example\n```ts\nconst { teams } = await snaptrude.workspace.teams.list()\nfor (const t of teams) console.log(t.id, t.name)\n```"
7687
+ ],
7688
+ "argsType": null,
7689
+ "resultType": "PluginWorkspaceTeamsListResult"
7690
+ },
7691
+ {
7692
+ "path": "workspace.teams.listMembers",
7693
+ "namespace": "workspace.teams",
7694
+ "summary": "List the members of a team.",
7695
+ "examplePrompts": [
7696
+ "List the members of the Acme team",
7697
+ "Who is on team_1?",
7698
+ "How many people are in this team?\n\n# Example\n```ts\nconst { members } = await snaptrude.workspace.teams.listMembers(\"team_1\")\nfor (const m of members) console.log(m.name, m.email)\n```"
7699
+ ],
7700
+ "argsType": "string",
7701
+ "resultType": "PluginWorkspaceTeamsListMembersResult"
6441
7702
  }
6442
7703
  ]