@snaptrude/plugin-core 0.9.3 → 0.9.5

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.
package/api-manifest.json CHANGED
@@ -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",
@@ -412,6 +548,32 @@
412
548
  "argsType": "PluginStandardView",
413
549
  "resultType": "boolean"
414
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
+ },
415
577
  {
416
578
  "path": "core.comment.create",
417
579
  "namespace": "core.comment",
@@ -553,6 +715,183 @@
553
715
  "argsType": "Vec3Handle",
554
716
  "resultType": "ArcHandle"
555
717
  },
718
+ {
719
+ "path": "core.geom.create.brepFromChamfer",
720
+ "namespace": "core.geom.create",
721
+ "summary": "Bevels the given straight edges of a solid with a symmetric planar cut. Host API call — returns a new {@linkcode BrepHandle}; the input brep is read-only.",
722
+ "examplePrompts": [
723
+ "Bevel these edges by 100mm",
724
+ "Chamfer the top edges of the plinth",
725
+ "Cut a 45-degree flat along the corners of this mass\n\n# Example\n```ts\nconst brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)\nconst edges = await snaptrude.core.geom.query.brep.listEdges(brep)\nconst beveled = await snaptrude.core.geom.create.brepFromChamfer(brep, [edges[0]], 0.1)\n```"
726
+ ],
727
+ "argsType": "BrepHandle",
728
+ "resultType": "BrepHandle"
729
+ },
730
+ {
731
+ "path": "core.geom.create.brepFromExtrusion",
732
+ "namespace": "core.geom.create",
733
+ "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).",
734
+ "examplePrompts": [
735
+ "Extrude this profile 3 metres up",
736
+ "Make a solid by extruding this outline",
737
+ "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```"
738
+ ],
739
+ "argsType": "ContourHandle",
740
+ "resultType": "BrepHandle"
741
+ },
742
+ {
743
+ "path": "core.geom.create.brepFromFaces",
744
+ "namespace": "core.geom.create",
745
+ "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.",
746
+ "examplePrompts": [
747
+ "Create a brep from faces",
748
+ "Build a custom solid from a set of faces",
749
+ "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```"
750
+ ],
751
+ "argsType": "Vec3Components[][]",
752
+ "resultType": "BrepHandle"
753
+ },
754
+ {
755
+ "path": "core.geom.create.brepFromFillet",
756
+ "namespace": "core.geom.create",
757
+ "summary": "Rounds the given straight edges of a solid with a constant radius. Host API call — returns a new {@linkcode BrepHandle}; the input brep is read-only.",
758
+ "examplePrompts": [
759
+ "Round the edges of this mass",
760
+ "Fillet the corners of the podium with a 0.5m radius",
761
+ "Soften the vertical edges of this tower\n\n# Example\n```ts\nconst brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)\nconst edges = await snaptrude.core.geom.query.brep.listEdges(brep)\nconst rounded = await snaptrude.core.geom.create.brepFromFillet(brep, [edges[0]], 0.3)\n```"
762
+ ],
763
+ "argsType": "BrepHandle",
764
+ "resultType": "BrepHandle"
765
+ },
766
+ {
767
+ "path": "core.geom.create.brepFromIntersection",
768
+ "namespace": "core.geom.create",
769
+ "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.",
770
+ "examplePrompts": [
771
+ "Keep only the overlap of these two solids",
772
+ "Intersect these two masses",
773
+ "Clip the tower to the zoning envelope\n\n# Example\n```ts\nconst overlap = await snaptrude.core.geom.create.brepFromIntersection(towerBrep, envelopeBrep)\n```"
774
+ ],
775
+ "argsType": "BrepHandle",
776
+ "resultType": "BrepHandle"
777
+ },
778
+ {
779
+ "path": "core.geom.create.brepFromLoft",
780
+ "namespace": "core.geom.create",
781
+ "summary": "Create a closed solid **B-rep** by lofting between a bottom and a top contour, optionally through intermediate cross-sections. Host API call — returns a {@linkcode BrepHandle}. Sections with different edge counts are auto-matched: vertices are deterministically inserted on the smaller sections at the larger section's perimeter positions, so the same input always yields the same solid. For straight-edge (all-line) sections the seam is auto-aligned too — winding and start-vertex correspondence are chosen to avoid a twist, so outlines authored from any starting corner loft cleanly; arc-bearing sections keep the authored correspondence unchanged. A pair whose side faces would be non-planar under every correspondence still builds for hole-free straight-edged pairs — planar side quads stay quads and warped ones split into planar triangles (the triangulated lane); arc-bearing or holed twisted pairs are rejected, as is auto-matching that would pair an arc with a straight edge. Matching hole counts are allowed in the two-section form. With intermediates the loft is a chain of ruled segments folded into one solid: sections must be planar and hole-free, ordered bottom → intermediates → top. The contours are copied — the input handles are never mutated.",
782
+ "examplePrompts": [
783
+ "Make a tapered tower from these two outlines",
784
+ "Loft between a large base and a smaller top",
785
+ "Create a frustum from two squares",
786
+ "Loft the tower through these three floor outlines",
787
+ "Loft a four-sided base to a five-sided top",
788
+ "Loft these outlines even though their corners don't line up",
789
+ "Loft these outlines exactly as authored, corner to corner",
790
+ "Fail the loft if my sections don't have matching edge counts\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```"
791
+ ],
792
+ "argsType": "ContourHandle",
793
+ "resultType": "BrepHandle"
794
+ },
795
+ {
796
+ "path": "core.geom.create.brepFromMesh",
797
+ "namespace": "core.geom.create",
798
+ "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.",
799
+ "examplePrompts": [
800
+ "Create a brep from mesh vertices and indices",
801
+ "Turn this indexed mesh into a solid",
802
+ "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```"
803
+ ],
804
+ "argsType": "Vec3Components[]",
805
+ "resultType": "BrepHandle"
806
+ },
807
+ {
808
+ "path": "core.geom.create.brepFromOffset",
809
+ "namespace": "core.geom.create",
810
+ "summary": "Grows or shrinks a solid by offsetting every face — positive distance moves faces outward, negative moves them inward. Host API call — returns a new {@linkcode BrepHandle}; the input brep is read-only.",
811
+ "examplePrompts": [
812
+ "Grow this solid by 0.5m in every direction",
813
+ "Shrink this mass by 200mm",
814
+ "Offset the building envelope outward by 1m\n\n# Example\n```ts\nconst brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)\nconst grown = await snaptrude.core.geom.create.brepFromOffset(brep, 0.5)\n```"
815
+ ],
816
+ "argsType": "BrepHandle",
817
+ "resultType": "BrepHandle"
818
+ },
819
+ {
820
+ "path": "core.geom.create.brepFromRevolution",
821
+ "namespace": "core.geom.create",
822
+ "summary": "Revolves a planar profile about an axis to make a solid of revolution — a full turn by default. Host API call — returns a new {@linkcode BrepHandle}; the input contour is read-only. Holes in the profile are allowed. Profile segments must stay parallel or perpendicular to the axis — inclined or arc segments would revolve into surfaces Snaptrude cannot represent.",
823
+ "examplePrompts": [
824
+ "Create a dome from this section",
825
+ "Revolve this profile 360 degrees around the vertical axis",
826
+ "Build a rotunda by revolving this wall section\n\n# Example\n```ts\n// A cylinder: revolve a 2m-wide, 3m-tall rectangle about the Y axis at its edge\nconst rect = await snaptrude.core.geom.create.profileFromLinePoints([\nawait snaptrude.core.math.vec3.new(0, 0, 0),\nawait snaptrude.core.math.vec3.new(2, 0, 0),\nawait snaptrude.core.math.vec3.new(2, 3, 0),\nawait snaptrude.core.math.vec3.new(0, 3, 0),\n])\nconst profile = await snaptrude.core.geom.create.contourFromProfile(rect)\nconst cylinder = await snaptrude.core.geom.create.brepFromRevolution(\nprofile,\n{ x: 0, y: 0, z: 0 },\n{ x: 0, y: 1, z: 0 },\n)\n```"
827
+ ],
828
+ "argsType": "ContourHandle",
829
+ "resultType": "BrepHandle"
830
+ },
831
+ {
832
+ "path": "core.geom.create.brepFromShell",
833
+ "namespace": "core.geom.create",
834
+ "summary": "Hollows a solid into constant-thickness walls, removing the given faces as openings. Host API call — returns a new {@linkcode BrepHandle}; the input brep is read-only. The outer surface is kept and the walls grow inward.",
835
+ "examplePrompts": [
836
+ "Hollow this mass into 200mm walls",
837
+ "Shell this form with the top face open",
838
+ "Turn this solid tower into a tube open at both ends\n\n# Example\n```ts\nconst brep = await snaptrude.core.geom.create.brepFromExtrusion(contour, { x: 0, y: 1, z: 0 }, 3)\nconst faces = await snaptrude.core.geom.query.brep.listFaces(brep)\nconst hollow = await snaptrude.core.geom.create.brepFromShell(brep, [faces[0]], 0.2)\n```"
839
+ ],
840
+ "argsType": "BrepHandle",
841
+ "resultType": "BrepHandle"
842
+ },
843
+ {
844
+ "path": "core.geom.create.brepFromSubtraction",
845
+ "namespace": "core.geom.create",
846
+ "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.",
847
+ "examplePrompts": [
848
+ "Subtract the courtyard from the building mass",
849
+ "Cut this solid out of that one",
850
+ "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```"
851
+ ],
852
+ "argsType": "BrepHandle",
853
+ "resultType": "BrepHandle"
854
+ },
855
+ {
856
+ "path": "core.geom.create.brepFromSweep",
857
+ "namespace": "core.geom.create",
858
+ "summary": "Sweeps a planar profile along a polyline path, with mitred corners at each bend. Host API call — returns a new {@linkcode BrepHandle}; the input contour is read-only. The profile must be hole-free and must not lie in a plane containing the first path segment's direction. Repeating the first point as the last closes the path into a ring solid (a picture frame): closed paths must be flat and straight-segmented and take a straight-edged (arc-free) profile — the ring's cross-section is the authored profile projected along the first leg onto the first mitre plane, so a profile not perpendicular to the first leg appears sheared. An optional scale law tapers the sweep: `startScale`/`endScale` interpolate linearly by arc length, or `scales` gives one factor per path point (scaling is about the profile centroid). A uniform scale (all factors equal) works on any path today's sweep accepts; a varying scale takes straight (collinear) open paths with straight-edged profiles — tapering across a bend or along an arc edge would create faces Snaptrude cannot represent and throws (sweep each straight run separately and union the results instead). An optional `transition` picks the corner treatment: `\"miter\"` (default) is today's sharp mitred bend; `{ bevel: b }` chamfers each turning corner by cutting `b` back along both adjacent legs (works on open and closed paths — each leg must be long enough for its cuts). On a corner-less path `transition` has no effect, and the varying-scale lane takes straight paths, so it never sees a corner.",
859
+ "examplePrompts": [
860
+ "Sweep this profile along the corridor path",
861
+ "Extrude the railing section along this route",
862
+ "Run a duct profile through these points",
863
+ "Sweep a frame profile around a closed rectangular loop",
864
+ "Taper this duct from 1x1 to 2x2 along its run",
865
+ "Sweep a column section that narrows toward the top",
866
+ "Chamfer the corners of this swept frame by 200mm\n\n# Example\n```ts\nconst rect = await snaptrude.core.geom.create.profileRect(0.4, 0.4)\nconst profile = await snaptrude.core.geom.create.contourFromProfile(rect)\n// profileRect lies in the XZ plane, so the path must START out of that\n// plane (here: straight up), then it can run horizontally.\nconst duct = await snaptrude.core.geom.create.brepFromSweep(profile, [\n{ x: 0, y: 0, z: 0 },\n{ x: 0, y: 2.8, z: 0 },\n{ x: 10, y: 2.8, z: 0 },\n])\n// A closed ring (picture frame): repeat the first point as the last\nconst frame = await snaptrude.core.geom.create.brepFromSweep(profile, [\n{ x: 0, y: 0, z: 0 },\n{ x: 0, y: 3, z: 0 },\n{ x: 4, y: 3, z: 0 },\n{ x: 4, y: 0, z: 0 },\n{ x: 0, y: 0, z: 0 },\n])\n// A tapered straight run: 0.4x0.4 at the start, 0.8x0.8 at the end\nconst flue = await snaptrude.core.geom.create.brepFromSweep(\nprofile,\n[\n{ x: 0, y: 0, z: 0 },\n{ x: 0, y: 10, z: 0 },\n],\n{ startScale: 1, endScale: 2 },\n)\n```"
867
+ ],
868
+ "argsType": "ContourHandle",
869
+ "resultType": "BrepHandle"
870
+ },
871
+ {
872
+ "path": "core.geom.create.brepFromUnion",
873
+ "namespace": "core.geom.create",
874
+ "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.",
875
+ "examplePrompts": [
876
+ "Union these two solids",
877
+ "Merge these breps into one mass",
878
+ "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```"
879
+ ],
880
+ "argsType": "BrepHandle",
881
+ "resultType": "BrepHandle"
882
+ },
883
+ {
884
+ "path": "core.geom.create.brepsFromSplit",
885
+ "namespace": "core.geom.create",
886
+ "summary": "Cuts a solid by an infinite plane and returns one brep per resulting piece — a single piece if the plane misses the solid. Host API call — returns new {@linkcode BrepHandle}s; the input brep is read-only. The plane is defined by a point on it and its normal direction.",
887
+ "examplePrompts": [
888
+ "Cut this building at 12m height",
889
+ "Split the tower from the podium with a horizontal plane",
890
+ "Slice this mass along a vertical plane\n\n# Example\n```ts\nconst pieces = await snaptrude.core.geom.create.brepsFromSplit(\ntowerBrep,\n{ x: 0, y: 12, z: 0 },\n{ x: 0, y: 1, z: 0 },\n)\nconsole.log(\"pieces:\", pieces.length)\n```"
891
+ ],
892
+ "argsType": "BrepHandle",
893
+ "resultType": "BrepHandle[]"
894
+ },
556
895
  {
557
896
  "path": "core.geom.create.circle",
558
897
  "namespace": "core.geom.create",
@@ -632,7 +971,8 @@
632
971
  "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.",
633
972
  "examplePrompts": [],
634
973
  "argsType": "ContourHandle",
635
- "resultType": "void"
974
+ "resultType": "void",
975
+ "deprecated": "core.handles.release"
636
976
  },
637
977
  {
638
978
  "path": "core.geom.delete.profile",
@@ -640,7 +980,8 @@
640
980
  "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.",
641
981
  "examplePrompts": [],
642
982
  "argsType": "ProfileHandle",
643
- "resultType": "void"
983
+ "resultType": "void",
984
+ "deprecated": "core.handles.release"
644
985
  },
645
986
  {
646
987
  "path": "core.geom.query.arc.getAxis",
@@ -713,6 +1054,18 @@
713
1054
  "argsType": "BrepHandle",
714
1055
  "resultType": "Vec3Components"
715
1056
  },
1057
+ {
1058
+ "path": "core.geom.query.brep.getDistance",
1059
+ "namespace": "core.geom.query.brep",
1060
+ "summary": "Measures the minimum distance between two solids, with the closest witness point on each. Touching or overlapping solids report a distance of 0 with contact points.",
1061
+ "examplePrompts": [
1062
+ "What is the clearance between these two masses?",
1063
+ "How far apart are the tower and the neighbouring building?",
1064
+ "Find the closest points between these two solids\n\n# Example\n```ts\nconst [a, b] = await snaptrude.design.query.listMasses()\nconst brepA = await snaptrude.design.query.geometry.getBrep(a)\nconst brepB = await snaptrude.design.query.geometry.getBrep(b)\nif (brepA && brepB) {\nconst { distance, pointA, pointB } = await snaptrude.core.geom.query.brep.getDistance(brepA, brepB)\nconsole.log(\"clearance:\", distance)\n}\n```"
1065
+ ],
1066
+ "argsType": "BrepHandle",
1067
+ "resultType": "{ distance: number; pointA: Vec3Components; pointB: Vec3Components }"
1068
+ },
716
1069
  {
717
1070
  "path": "core.geom.query.brep.getEdge",
718
1071
  "namespace": "core.geom.query.brep",
@@ -729,6 +1082,19 @@
729
1082
  "argsType": "BrepHandle",
730
1083
  "resultType": "number"
731
1084
  },
1085
+ {
1086
+ "path": "core.geom.query.brep.getEdgeCurve",
1087
+ "namespace": "core.geom.query.brep",
1088
+ "summary": "Read the exact curve of a brep edge as plain values — a discriminated union on `type`. Pure read: no geometry kernel is loaded. Points and directions are {@linkcode Vec3Components}; lengths and radii are raw Babylon units.",
1089
+ "examplePrompts": [
1090
+ "Read the radius of this curved edge",
1091
+ "Is this edge straight or an arc?",
1092
+ "Get the exact start and end points of this edge",
1093
+ "Measure the length of each edge of this mass\n\n# Example\n```ts\nconst [mass] = await snaptrude.design.query.listMasses()\nconst brep = await snaptrude.design.query.geometry.getBrep(mass)\nif (brep) {\nconst edges = await snaptrude.core.geom.query.brep.listEdges(brep)\nfor (const edge of edges) {\nconst curve = await snaptrude.core.geom.query.brep.getEdgeCurve(brep, edge)\nif (curve.type === \"arc\") console.log(\"arc radius:\", curve.radius)\n}\n}\n```"
1094
+ ],
1095
+ "argsType": "BrepHandle",
1096
+ "resultType": "| { type: \"line\"; startPoint: Vec3Components; endPoint: Vec3Components; length: number }\n | {\n type: \"arc\"\n startPoint: Vec3Components\n endPoint: Vec3Components\n centre: Vec3Components\n axis: Vec3Components\n radius: number\n length: number\n }\n | {\n type: \"circle\"\n centre: Vec3Components\n axis: Vec3Components\n radius: number\n length: number\n }"
1097
+ },
732
1098
  {
733
1099
  "path": "core.geom.query.brep.getFaceCount",
734
1100
  "namespace": "core.geom.query.brep",
@@ -2220,6 +2586,18 @@
2220
2586
  "argsType": "string",
2221
2587
  "resultType": "ImportJobHandle"
2222
2588
  },
2589
+ {
2590
+ "path": "core.io.import.epw",
2591
+ "namespace": "core.io.import",
2592
+ "summary": "Import an **EPW weather file** into the project's weather catalog.",
2593
+ "examplePrompts": [
2594
+ "Import this EPW weather file for the site",
2595
+ "Upload a custom weather file for the daylight analysis",
2596
+ "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```"
2597
+ ],
2598
+ "argsType": "string",
2599
+ "resultType": "PluginImportEpwResult"
2600
+ },
2223
2601
  {
2224
2602
  "path": "core.io.import.image",
2225
2603
  "namespace": "core.io.import",
@@ -2490,6 +2868,19 @@
2490
2868
  "argsType": null,
2491
2869
  "resultType": "boolean | null"
2492
2870
  },
2871
+ {
2872
+ "path": "core.io.terrain.replaceMesh",
2873
+ "namespace": "core.io.terrain",
2874
+ "summary": "Replace the terrain surface with a caller-supplied triangle mesh. Undoable (one step), and the replacement persists with the project. The returned promise resolves only after the surface is fully applied and recorded — it is safe to toggle terrain resolution or read the surface back the moment it resolves.",
2875
+ "examplePrompts": [
2876
+ "Replace the terrain with this surveyed mesh",
2877
+ "Flatten a building pad into the site surface",
2878
+ "Load a custom DEM surface onto the terrain",
2879
+ "Regrade the terrain from these points\n\n# Example\n```ts\n// Projects with no terrain yet: import first, then replace.\nif (!(await snaptrude.core.io.terrain.exists())) {\nawait snaptrude.core.io.import.terrain(40.7128, -74.006, 300, 300)\n}\nconst result = await snaptrude.core.io.terrain.replaceMesh(\npositions, // [x0, y0, z0, x1, y1, z1, …] — world space\nindices, // [a0, b0, c0, a1, b1, c1, …]\n\"meters\",\n{\ncoordinateSpace: \"world\",\nexpectedTerrain: await snaptrude.core.io.terrain.get(),\nbaseline: \"make-replacement-original\",\npreserve: { datum: true, geolocation: true, satellite: true, material: true },\nclientMutationId: \"survey-2026-08-05-r1\",\n},\n)\n// result.modelRevision — pass back as expectedModelRevision on the next call\n```"
2880
+ ],
2881
+ "argsType": "number[]",
2882
+ "resultType": "PluginTerrainReplaceMeshResult"
2883
+ },
2493
2884
  {
2494
2885
  "path": "core.io.terrain.setDatum",
2495
2886
  "namespace": "core.io.terrain",
@@ -2516,6 +2907,19 @@
2516
2907
  "argsType": "number",
2517
2908
  "resultType": "void"
2518
2909
  },
2910
+ {
2911
+ "path": "core.io.underlay.classifyArcs",
2912
+ "namespace": "core.io.underlay",
2913
+ "summary": "Classify one retained AutoCAD layer's **arcs as door swings** — the deterministic tracing primitive behind CAD-to-BIM door placement. A door swing is drawn as a ~90° arc whose radius IS the leaf width and whose centre IS the hinge point. This filters the layer's arcs by plausible radius and sweep (rejecting inch-scale fillets, full-circle symbols and long shallow curves), reads each survivor as a door candidate (hinge, leaf width, swing direction, hosting wall direction), merges mirrored pairs sharing a chord line into double doors, and returns a radius histogram — real drawings use a handful of standard door sizes, so the histogram's clusters are the drawing's door widths (sanity-check them against the catalog; distrust arcs in no cluster).",
2914
+ "examplePrompts": [
2915
+ "Find the doors on the a-door CAD layer",
2916
+ "Classify the door swing arcs in the imported drawing",
2917
+ "What door sizes does this DWG use?",
2918
+ "Read hinge points and leaf widths from the CAD door layer\n\n# Example\n```ts\nconst [cad] = await snaptrude.core.io.underlay.list()\nconst r = await snaptrude.core.io.underlay.classifyArcs(cad, \"a-door\")\nif (r) {\nconsole.log(`${r.doors.length} doors; sizes:`,\nr.radiusHistogram.filter((b) => b.count > 1))\n}\n```"
2919
+ ],
2920
+ "argsType": "UnderlayHandle",
2921
+ "resultType": "PluginCadArcClassifyResult | null"
2922
+ },
2519
2923
  {
2520
2924
  "path": "core.io.underlay.delete",
2521
2925
  "namespace": "core.io.underlay",
@@ -2529,6 +2933,19 @@
2529
2933
  "argsType": "UnderlayHandle",
2530
2934
  "resultType": "void"
2531
2935
  },
2936
+ {
2937
+ "path": "core.io.underlay.extractCenterlines",
2938
+ "namespace": "core.io.underlay",
2939
+ "summary": "Extract **continuous wall centrelines** from one retained AutoCAD layer's double-line wall faces — the deterministic tracing primitive behind CAD-to-BIM wall conversion. Instead of paging raw curves and re-deriving the geometry in worker code, this reads the whole layer and runs the vetted pipeline: cull fragments, dedupe, merge collinear runs into *faces*, pair parallel faces a wall-thickness apart into centrelines (midline = axis, separation = thickness), bridge collinear gaps up to `bridgeOpenings.maxWidth` into ONE continuous centreline while recording each bridged span as an opening, then snap near-touching endpoints at junctions.",
2940
+ "examplePrompts": [
2941
+ "Trace the walls from the a-wall CAD layer",
2942
+ "Convert the AutoCAD wall linework into Snaptrude walls",
2943
+ "Extract wall centrelines with thickness from the imported DWG",
2944
+ "Find the glazing runs on the a-glazing layer\n\n# Example\n```ts\nconst [cad] = await snaptrude.core.io.underlay.list()\nconst r = await snaptrude.core.io.underlay.extractCenterlines(cad, \"a-wall\")\nif (r) {\nconst items = r.centerlines.map((c) => ({\nprofile: [c.start, c.end],\nthickness: c.thickness,\n}))\nconsole.log(`${items.length} walls, ${r.unpaired.length} unpaired faces`)\n}\n```"
2945
+ ],
2946
+ "argsType": "UnderlayHandle",
2947
+ "resultType": "PluginCadCenterlinesResult | null"
2948
+ },
2532
2949
  {
2533
2950
  "path": "core.io.underlay.getBounds",
2534
2951
  "namespace": "core.io.underlay",
@@ -2542,6 +2959,17 @@
2542
2959
  "argsType": "UnderlayHandle",
2543
2960
  "resultType": "BBoxComponents | null"
2544
2961
  },
2962
+ {
2963
+ "path": "core.io.underlay.getCadLayerGeometry",
2964
+ "namespace": "core.io.underlay",
2965
+ "summary": "Read one original AutoCAD layer's retained line and arc geometry in **Snaptrude world space** and Snaptrude internal units. Results are paged so large drawings can be inspected without returning the whole DWG at once.",
2966
+ "examplePrompts": [
2967
+ "Read the wall geometry from the A-WALL layer in this CAD underlay",
2968
+ "Get the next 500 curves from the structural CAD layer\n\n# Example\n```ts\nconst page = await snaptrude.core.io.underlay.getCadLayerGeometry(\ncad,\n\"A-WALL\",\n{ offset: 0, limit: 500 },\n)\nif (page) console.log(`${page.curves.length} of ${page.total} curves`)\n```"
2969
+ ],
2970
+ "argsType": "UnderlayHandle",
2971
+ "resultType": "PluginCadLayerGeometryPage | null"
2972
+ },
2545
2973
  {
2546
2974
  "path": "core.io.underlay.getOpacity",
2547
2975
  "namespace": "core.io.underlay",
@@ -2581,6 +3009,17 @@
2581
3009
  "argsType": "number",
2582
3010
  "resultType": "UnderlayHandle[]"
2583
3011
  },
3012
+ {
3013
+ "path": "core.io.underlay.listCadLayers",
3014
+ "namespace": "core.io.underlay",
3015
+ "summary": "List the distinct original AutoCAD layer names retained by a placed CAD underlay. Returns `[]` for non-CAD underlays, legacy imports created before source-layer retention, missing underlays, or CAD drawings without layer tags.",
3016
+ "examplePrompts": [
3017
+ "List the original AutoCAD layers in this imported drawing",
3018
+ "Which CAD layers are available in this underlay?\n\n# Example\n```ts\nconst layers = await snaptrude.core.io.underlay.listCadLayers(cad)\nconsole.log(layers)\n```"
3019
+ ],
3020
+ "argsType": "UnderlayHandle",
3021
+ "resultType": "string[]"
3022
+ },
2584
3023
  {
2585
3024
  "path": "core.io.underlay.resetScale",
2586
3025
  "namespace": "core.io.underlay",
@@ -2923,6 +3362,41 @@
2923
3362
  "argsType": "Vec3Handle",
2924
3363
  "resultType": "Vec3Handle"
2925
3364
  },
3365
+ {
3366
+ "path": "core.mode.get",
3367
+ "namespace": "core.mode",
3368
+ "summary": "Get the currently active application mode.",
3369
+ "examplePrompts": [
3370
+ "Which mode am I in right now?",
3371
+ "Am I in present mode?",
3372
+ "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```"
3373
+ ],
3374
+ "argsType": null,
3375
+ "resultType": "PluginAppMode"
3376
+ },
3377
+ {
3378
+ "path": "core.mode.list",
3379
+ "namespace": "core.mode",
3380
+ "summary": "List every application mode the editor has.",
3381
+ "examplePrompts": [
3382
+ "What modes does Snaptrude have?",
3383
+ "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```"
3384
+ ],
3385
+ "argsType": null,
3386
+ "resultType": "PluginCoreModeListResult"
3387
+ },
3388
+ {
3389
+ "path": "core.mode.set",
3390
+ "namespace": "core.mode",
3391
+ "summary": "Switch the editor to another application mode — the same action as clicking that tab in the top menu bar.",
3392
+ "examplePrompts": [
3393
+ "Switch to present mode",
3394
+ "Open BIM mode",
3395
+ "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```"
3396
+ ],
3397
+ "argsType": "PluginAppMode",
3398
+ "resultType": "PluginCoreModeSetResult"
3399
+ },
2926
3400
  {
2927
3401
  "path": "core.project.settings.getTolerance",
2928
3402
  "namespace": "core.project.settings",
@@ -3293,39 +3767,131 @@
3293
3767
  "resultType": "PluginCoreProposalsSetActiveResult"
3294
3768
  },
3295
3769
  {
3296
- "path": "core.tags.assign",
3297
- "namespace": "core.tags",
3298
- "summary": "Assign a tag to components, creating the category and tag if needed.",
3770
+ "path": "core.storeys.copy",
3771
+ "namespace": "core.storeys",
3772
+ "summary": "Copy a storey into the adjacent level, up or down.",
3299
3773
  "examplePrompts": [
3300
- "Tag the selected spaces as Retail in the Zone category",
3301
- "Tag these rooms High Priority, creating the tag if it doesn't exist",
3302
- "Put cmp_1 and cmp_2 in Zone / Retail\n\n# Example\n```ts\nconst { tagId, tagCreated, assigned } = await snaptrude.core.tags.assign(\n[\"cmp_1\", \"cmp_2\"],\n\"Zone\",\n\"Retail\",\n)\n```"
3774
+ "Copy this floor to the storey above",
3775
+ "Copy the ground floor down into a new basement",
3776
+ "Repeat this level upwards with its own independent geometry",
3777
+ "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```"
3303
3778
  ],
3304
- "argsType": "ComponentHandle[]",
3305
- "resultType": "PluginCoreTagsAssignResult"
3779
+ "argsType": "\"up\" | \"down\"",
3780
+ "resultType": "PluginStoryDuplicateResult"
3306
3781
  },
3307
3782
  {
3308
- "path": "core.tags.create",
3309
- "namespace": "core.tags",
3310
- "summary": "Create a new tag in a category.",
3783
+ "path": "core.storeys.create",
3784
+ "namespace": "core.storeys",
3785
+ "summary": "Create a new storey (floor) in the project.",
3311
3786
  "examplePrompts": [
3312
- "Add a tag called 2-hour to the Fire Rating category",
3313
- "Create a red High Priority tag in category cat_3",
3314
- "Make a new tag named Retail\n\n# Example\n```ts\nconst tag = await snaptrude.core.tags.create(\"cat_3\", \"Retail\", \"#b5e1dc\")\n```"
3787
+ "Add a third floor to the building",
3788
+ "Create a new storey above the second floor",
3789
+ "Add a basement level to this project",
3790
+ "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```"
3315
3791
  ],
3316
- "argsType": "string",
3317
- "resultType": "PluginCoreTagsCreateResult"
3792
+ "argsType": "number",
3793
+ "resultType": "PluginStoryCreateResult"
3318
3794
  },
3319
3795
  {
3320
- "path": "core.tags.createCategory",
3321
- "namespace": "core.tags",
3322
- "summary": "Create a new tag category.",
3796
+ "path": "core.storeys.delete",
3797
+ "namespace": "core.storeys",
3798
+ "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.",
3323
3799
  "examplePrompts": [
3324
- "Create a tag category called Fire Rating",
3325
- "Add a new category named Zone",
3326
- "Make a category for occupancy type\n\n# Example\n```ts\nconst category = await snaptrude.core.tags.createCategory(\"Fire Rating\")\n```"
3327
- ],
3328
- "argsType": "string",
3800
+ "Delete the top floor",
3801
+ "Remove the basement level",
3802
+ "Get rid of storey 3",
3803
+ "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```"
3804
+ ],
3805
+ "argsType": "number",
3806
+ "resultType": "PluginStoryDeleteResult"
3807
+ },
3808
+ {
3809
+ "path": "core.storeys.get",
3810
+ "namespace": "core.storeys",
3811
+ "summary": "Get properties of a storey by its storey number.",
3812
+ "examplePrompts": [
3813
+ "What is the height of the ground floor?",
3814
+ "How many rooms are on the second storey?",
3815
+ "Get the total floor area of level 3",
3816
+ "Is the first floor hidden in the viewport?",
3817
+ "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```"
3818
+ ],
3819
+ "argsType": "number",
3820
+ "resultType": "PluginStoryGetResult"
3821
+ },
3822
+ {
3823
+ "path": "core.storeys.list",
3824
+ "namespace": "core.storeys",
3825
+ "summary": "List all storeys in the current project.",
3826
+ "examplePrompts": [
3827
+ "How many floors does this building have?",
3828
+ "List all the storeys in the project",
3829
+ "Show me every level with its name",
3830
+ "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```"
3831
+ ],
3832
+ "argsType": null,
3833
+ "resultType": "PluginCoreStoreysListResult"
3834
+ },
3835
+ {
3836
+ "path": "core.storeys.setActive",
3837
+ "namespace": "core.storeys",
3838
+ "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.",
3839
+ "examplePrompts": [
3840
+ "Switch to the second floor",
3841
+ "Make the ground storey active",
3842
+ "Go to the basement level",
3843
+ "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```"
3844
+ ],
3845
+ "argsType": "number",
3846
+ "resultType": "PluginStorySetActiveResult"
3847
+ },
3848
+ {
3849
+ "path": "core.storeys.update",
3850
+ "namespace": "core.storeys",
3851
+ "summary": "Update a storey's floor-to-floor `height` and/or `name`.",
3852
+ "examplePrompts": [
3853
+ "Change the ground floor height to 3.5 metres",
3854
+ "Make the second storey taller",
3855
+ "Rename the ground floor to \"Lobby\"",
3856
+ "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```"
3857
+ ],
3858
+ "argsType": "number",
3859
+ "resultType": "PluginStoryUpdateResult"
3860
+ },
3861
+ {
3862
+ "path": "core.tags.assign",
3863
+ "namespace": "core.tags",
3864
+ "summary": "Assign a tag to components, creating the category and tag if needed.",
3865
+ "examplePrompts": [
3866
+ "Tag the selected spaces as Retail in the Zone category",
3867
+ "Tag these rooms High Priority, creating the tag if it doesn't exist",
3868
+ "Put cmp_1 and cmp_2 in Zone / Retail\n\n# Example\n```ts\nconst { tagId, tagCreated, assigned } = await snaptrude.core.tags.assign(\n[\"cmp_1\", \"cmp_2\"],\n\"Zone\",\n\"Retail\",\n)\n```"
3869
+ ],
3870
+ "argsType": "ComponentHandle[]",
3871
+ "resultType": "PluginCoreTagsAssignResult"
3872
+ },
3873
+ {
3874
+ "path": "core.tags.create",
3875
+ "namespace": "core.tags",
3876
+ "summary": "Create a new tag in a category.",
3877
+ "examplePrompts": [
3878
+ "Add a tag called 2-hour to the Fire Rating category",
3879
+ "Create a red High Priority tag in category cat_3",
3880
+ "Make a new tag named Retail\n\n# Example\n```ts\nconst tag = await snaptrude.core.tags.create(\"cat_3\", \"Retail\", \"#b5e1dc\")\n```"
3881
+ ],
3882
+ "argsType": "string",
3883
+ "resultType": "PluginCoreTagsCreateResult"
3884
+ },
3885
+ {
3886
+ "path": "core.tags.createCategory",
3887
+ "namespace": "core.tags",
3888
+ "summary": "Create a new tag category.",
3889
+ "examplePrompts": [
3890
+ "Create a tag category called Fire Rating",
3891
+ "Add a new category named Zone",
3892
+ "Make a category for occupancy type\n\n# Example\n```ts\nconst category = await snaptrude.core.tags.createCategory(\"Fire Rating\")\n```"
3893
+ ],
3894
+ "argsType": "string",
3329
3895
  "resultType": "PluginCoreTagsCreateCategoryResult"
3330
3896
  },
3331
3897
  {
@@ -3386,7 +3952,8 @@
3386
3952
  "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```"
3387
3953
  ],
3388
3954
  "argsType": "ComponentHandle",
3389
- "resultType": "PluginCoreTagsGetTagsForComponentResult"
3955
+ "resultType": "PluginCoreTagsGetTagsForComponentResult",
3956
+ "deprecated": "core.tags.listForComponent"
3390
3957
  },
3391
3958
  {
3392
3959
  "path": "core.tags.list",
@@ -3424,6 +3991,18 @@
3424
3991
  "argsType": "{ tagId?: string; categoryId?: string; untagged?: boolean }",
3425
3992
  "resultType": "PluginCoreTagsListComponentsResult"
3426
3993
  },
3994
+ {
3995
+ "path": "core.tags.listForComponent",
3996
+ "namespace": "core.tags",
3997
+ "summary": "List the tags carried by a component.",
3998
+ "examplePrompts": [
3999
+ "What tags does this space have?",
4000
+ "List the tags on component cmp_42",
4001
+ "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```"
4002
+ ],
4003
+ "argsType": "ComponentHandle",
4004
+ "resultType": "PluginCoreTagsGetTagsForComponentResult"
4005
+ },
3427
4006
  {
3428
4007
  "path": "core.tags.unassign",
3429
4008
  "namespace": "core.tags",
@@ -3550,7 +4129,8 @@
3550
4129
  "Show me the full scene\n\n# Example\n```ts\nawait snaptrude.core.zoom.extents()\n```"
3551
4130
  ],
3552
4131
  "argsType": null,
3553
- "resultType": "boolean"
4132
+ "resultType": "boolean",
4133
+ "deprecated": "core.camera.zoomExtents"
3554
4134
  },
3555
4135
  {
3556
4136
  "path": "core.zoom.selection",
@@ -3563,7 +4143,8 @@
3563
4143
  "Fit the view to the selected room\n\n# Example\n```ts\nawait snaptrude.core.zoom.selection()\n```"
3564
4144
  ],
3565
4145
  "argsType": null,
3566
- "resultType": "boolean"
4146
+ "resultType": "boolean",
4147
+ "deprecated": "core.camera.zoomSelection"
3567
4148
  },
3568
4149
  {
3569
4150
  "path": "design.boolean.intersect",
@@ -3619,6 +4200,19 @@
3619
4200
  "argsType": "ContourHandle",
3620
4201
  "resultType": "ComponentHandle"
3621
4202
  },
4203
+ {
4204
+ "path": "design.create.buildableEnvelope",
4205
+ "namespace": "design.create",
4206
+ "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).",
4207
+ "examplePrompts": [
4208
+ "Create a buildable envelope for my site",
4209
+ "Generate the zoning envelope with 10ft front setbacks",
4210
+ "Show the maximum buildable volume with a 150ft height limit",
4211
+ "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```"
4212
+ ],
4213
+ "argsType": "PluginBuildableEnvelopePolygonVertex[]",
4214
+ "resultType": "PluginBuildableEnvelopeCreateResult"
4215
+ },
3622
4216
  {
3623
4217
  "path": "design.create.ceiling",
3624
4218
  "namespace": "design.create",
@@ -3716,6 +4310,30 @@
3716
4310
  "argsType": "ContourHandle",
3717
4311
  "resultType": "ComponentHandle"
3718
4312
  },
4313
+ {
4314
+ "path": "design.create.massFromBrep",
4315
+ "namespace": "design.create",
4316
+ "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).",
4317
+ "examplePrompts": [
4318
+ "Create a mass from these faces",
4319
+ "Turn this custom brep into a scene mass",
4320
+ "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```"
4321
+ ],
4322
+ "argsType": "BrepHandle",
4323
+ "resultType": "ComponentHandle"
4324
+ },
4325
+ {
4326
+ "path": "design.create.opening",
4327
+ "namespace": "design.create",
4328
+ "summary": "Place a catalog **door or window** into a host wall with optional size overrides.",
4329
+ "examplePrompts": [
4330
+ "Add a 1m wide door to this wall here",
4331
+ "Place a window with a 0.9m sill height on the selected wall"
4332
+ ],
4333
+ "argsType": "PluginDesignCreateOpeningOptions",
4334
+ "resultType": "ComponentHandle",
4335
+ "performance": "Single-opening creator — use it for one hosted opening. A plural API is intentionally unavailable until host placement can be atomic. # Example ```ts const opening = await snaptrude.design.create.opening({ kind: \"window\", catalogId: windowType.id, hostWall: wall, position: await snaptrude.core.math.vec3.new(3, 0, 5), width: 1.2, height: 1.5, sillHeight: 0.9, }) ```"
4336
+ },
3719
4337
  {
3720
4338
  "path": "design.create.referenceLines",
3721
4339
  "namespace": "design.create",
@@ -4489,6 +5107,19 @@
4489
5107
  "argsType": "ComponentHandle",
4490
5108
  "resultType": "CurveHandle | null"
4491
5109
  },
5110
+ {
5111
+ "path": "design.query.geometry.getTriangulatedMeshes",
5112
+ "namespace": "design.query.geometry",
5113
+ "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.",
5114
+ "examplePrompts": [
5115
+ "Export the selected masses as a triangle mesh",
5116
+ "Get the raw vertices and triangles of this wall in world coordinates",
5117
+ "Give me the triangulated geometry of every space with its materials",
5118
+ "Compute the surface area of this roof from its triangles"
5119
+ ],
5120
+ "argsType": "ComponentHandle[]",
5121
+ "resultType": "PluginDesignQueryGeometryGetTriangulatedMeshesResult"
5122
+ },
4492
5123
  {
4493
5124
  "path": "design.query.getBoundingBox",
4494
5125
  "namespace": "design.query",
@@ -4847,6 +5478,19 @@
4847
5478
  "argsType": "ComponentHandle",
4848
5479
  "resultType": "PluginEntityMeasurements | null"
4849
5480
  },
5481
+ {
5482
+ "path": "design.query.referenceLines.get",
5483
+ "namespace": "design.query.referenceLines",
5484
+ "summary": "Get properties of a reference line by its ID.",
5485
+ "examplePrompts": [
5486
+ "Get the curve geometry of this reference line",
5487
+ "Where does this grid line run?",
5488
+ "Read the geometry of a guide line by its id",
5489
+ "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```"
5490
+ ],
5491
+ "argsType": "string",
5492
+ "resultType": "PluginReferenceLineGetResult"
5493
+ },
4850
5494
  {
4851
5495
  "path": "design.query.spaces.get",
4852
5496
  "namespace": "design.query.spaces",
@@ -4861,6 +5505,19 @@
4861
5505
  "argsType": "ComponentHandle",
4862
5506
  "resultType": "PluginDesignQuerySpacesGetResult"
4863
5507
  },
5508
+ {
5509
+ "path": "design.query.spaces.getEnclosure",
5510
+ "namespace": "design.query.spaces",
5511
+ "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.",
5512
+ "examplePrompts": [
5513
+ "What walls, floor and ceiling enclose this room?",
5514
+ "Which of this room's walls are external?",
5515
+ "List the doors and windows around the selected space",
5516
+ "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```"
5517
+ ],
5518
+ "argsType": "ComponentHandle",
5519
+ "resultType": "PluginSpaceEnclosure | null"
5520
+ },
4864
5521
  {
4865
5522
  "path": "design.query.spaces.getFootprint",
4866
5523
  "namespace": "design.query.spaces",
@@ -4874,6 +5531,19 @@
4874
5531
  "argsType": "ComponentHandle",
4875
5532
  "resultType": "ContourHandle | null"
4876
5533
  },
5534
+ {
5535
+ "path": "design.query.storeyOutline",
5536
+ "namespace": "design.query",
5537
+ "summary": "Compute the plan **outline of what is built on a storey** — the union of the storey's wall (by default) footprints as polygons-with-holes. This is the footprint-from-the-built-model query: by the time slabs are needed the walls exist, and the engine's own solids (snapped, joined and mitred at creation) are the cleanest wall network available — no CAD re-tracing.",
5538
+ "examplePrompts": [
5539
+ "What is the building footprint on the ground floor?",
5540
+ "Create a floor slab covering the whole storey",
5541
+ "Get the outline of the walls on storey 1",
5542
+ "How much area do the ground-floor walls enclose?\n\n# Example\n```ts\nconst r = await snaptrude.design.query.storeyOutline({ storey: 1 })\nconst main = r.footprints.find((f) => f.enclosed)\nif (main) {\nconst profile = await snaptrude.core.geom.create.profileFromLinePoints(\nmain.outline.map((p) => ({ x: p.x, y: 0, z: p.z })),\n)\n// → design.create.slab with the profile's contour\n}\n```"
5543
+ ],
5544
+ "argsType": "PluginStoreyOutlineOptions",
5545
+ "resultType": "PluginStoreyOutlineResult"
5546
+ },
4877
5547
  {
4878
5548
  "path": "design.selection.add",
4879
5549
  "namespace": "design.selection",
@@ -5067,6 +5737,19 @@
5067
5737
  "argsType": "ComponentHandle[]",
5068
5738
  "resultType": "PluginDesignChangeResult"
5069
5739
  },
5740
+ {
5741
+ "path": "design.update.buildableEnvelope",
5742
+ "namespace": "design.update",
5743
+ "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).",
5744
+ "examplePrompts": [
5745
+ "Change the envelope's height limit to 175 feet",
5746
+ "Update the setbacks on the buildable envelope",
5747
+ "Regenerate the zoning envelope with a new site boundary",
5748
+ "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```"
5749
+ ],
5750
+ "argsType": "string",
5751
+ "resultType": "PluginBuildableEnvelopeUpdateResult"
5752
+ },
5070
5753
  {
5071
5754
  "path": "design.update.ceiling",
5072
5755
  "namespace": "design.update",
@@ -5409,7 +6092,8 @@
5409
6092
  "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```"
5410
6093
  ],
5411
6094
  "argsType": "PluginBuildableEnvelopePolygonVertex[]",
5412
- "resultType": "PluginBuildableEnvelopeCreateResult"
6095
+ "resultType": "PluginBuildableEnvelopeCreateResult",
6096
+ "deprecated": "design.create.buildableEnvelope"
5413
6097
  },
5414
6098
  {
5415
6099
  "path": "entity.buildableEnvelope.update",
@@ -5423,7 +6107,8 @@
5423
6107
  "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```"
5424
6108
  ],
5425
6109
  "argsType": "string",
5426
- "resultType": "PluginBuildableEnvelopeUpdateResult"
6110
+ "resultType": "PluginBuildableEnvelopeUpdateResult",
6111
+ "deprecated": "design.update.buildableEnvelope"
5427
6112
  },
5428
6113
  {
5429
6114
  "path": "entity.referenceLine.createMulti",
@@ -5437,7 +6122,8 @@
5437
6122
  "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```"
5438
6123
  ],
5439
6124
  "argsType": "ProfileHandle",
5440
- "resultType": "PluginReferenceLineCreateMultiResult"
6125
+ "resultType": "PluginReferenceLineCreateMultiResult",
6126
+ "deprecated": "design.create.referenceLines"
5441
6127
  },
5442
6128
  {
5443
6129
  "path": "entity.referenceLine.delete",
@@ -5450,7 +6136,8 @@
5450
6136
  "Erase a reference line by its id\n\n# Example\n```ts\nawait snaptrude.entity.referenceLine.delete(\"some-ref-line-id\")\n```"
5451
6137
  ],
5452
6138
  "argsType": "string",
5453
- "resultType": "PluginReferenceLineDeleteResult"
6139
+ "resultType": "PluginReferenceLineDeleteResult",
6140
+ "deprecated": "design.delete.entities"
5454
6141
  },
5455
6142
  {
5456
6143
  "path": "entity.referenceLine.get",
@@ -5463,7 +6150,8 @@
5463
6150
  "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```"
5464
6151
  ],
5465
6152
  "argsType": "string",
5466
- "resultType": "PluginReferenceLineGetResult"
6153
+ "resultType": "PluginReferenceLineGetResult",
6154
+ "deprecated": "design.query.referenceLines.get"
5467
6155
  },
5468
6156
  {
5469
6157
  "path": "entity.referenceLine.getAll",
@@ -5476,7 +6164,8 @@
5476
6164
  "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```"
5477
6165
  ],
5478
6166
  "argsType": null,
5479
- "resultType": "PluginReferenceLineGetAllResult"
6167
+ "resultType": "PluginReferenceLineGetAllResult",
6168
+ "deprecated": "design.query.listReferenceLines"
5480
6169
  },
5481
6170
  {
5482
6171
  "path": "entity.story.create",
@@ -5490,7 +6179,8 @@
5490
6179
  "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```"
5491
6180
  ],
5492
6181
  "argsType": "number",
5493
- "resultType": "PluginStoryCreateResult"
6182
+ "resultType": "PluginStoryCreateResult",
6183
+ "deprecated": "core.storeys.create"
5494
6184
  },
5495
6185
  {
5496
6186
  "path": "entity.story.delete",
@@ -5503,7 +6193,8 @@
5503
6193
  "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```"
5504
6194
  ],
5505
6195
  "argsType": "number",
5506
- "resultType": "PluginStoryDeleteResult"
6196
+ "resultType": "PluginStoryDeleteResult",
6197
+ "deprecated": "core.storeys.delete"
5507
6198
  },
5508
6199
  {
5509
6200
  "path": "entity.story.duplicate",
@@ -5517,7 +6208,8 @@
5517
6208
  ],
5518
6209
  "argsType": "\"up\" | \"down\"",
5519
6210
  "resultType": "PluginStoryDuplicateResult",
5520
- "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`) ```"
6211
+ "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`) ```",
6212
+ "deprecated": "core.storeys.copy"
5521
6213
  },
5522
6214
  {
5523
6215
  "path": "entity.story.get",
@@ -5531,7 +6223,8 @@
5531
6223
  "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```"
5532
6224
  ],
5533
6225
  "argsType": "number",
5534
- "resultType": "PluginStoryGetResult"
6226
+ "resultType": "PluginStoryGetResult",
6227
+ "deprecated": "core.storeys.get"
5535
6228
  },
5536
6229
  {
5537
6230
  "path": "entity.story.getAll",
@@ -5544,7 +6237,8 @@
5544
6237
  "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```"
5545
6238
  ],
5546
6239
  "argsType": null,
5547
- "resultType": "PluginStoryGetAllResult"
6240
+ "resultType": "PluginStoryGetAllResult",
6241
+ "deprecated": "core.storeys.list"
5548
6242
  },
5549
6243
  {
5550
6244
  "path": "entity.story.setActive",
@@ -5557,7 +6251,8 @@
5557
6251
  "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```"
5558
6252
  ],
5559
6253
  "argsType": "number",
5560
- "resultType": "PluginStorySetActiveResult"
6254
+ "resultType": "PluginStorySetActiveResult",
6255
+ "deprecated": "core.storeys.setActive"
5561
6256
  },
5562
6257
  {
5563
6258
  "path": "entity.story.update",
@@ -5571,7 +6266,8 @@
5571
6266
  "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```"
5572
6267
  ],
5573
6268
  "argsType": "number",
5574
- "resultType": "PluginStoryUpdateResult"
6269
+ "resultType": "PluginStoryUpdateResult",
6270
+ "deprecated": "core.storeys.update"
5575
6271
  },
5576
6272
  {
5577
6273
  "path": "presentation.aiInspiration.cancelJob",
@@ -5840,6 +6536,18 @@
5840
6536
  "argsType": null,
5841
6537
  "resultType": "PluginPresentationDiagramsGenerateResult"
5842
6538
  },
6539
+ {
6540
+ "path": "presentation.diagrams.generateSite",
6541
+ "namespace": "presentation.diagrams",
6542
+ "summary": "Generate the site diagrams (location, streetview, climate) for the current model, creating new layout sheets.",
6543
+ "examplePrompts": [
6544
+ "Generate the site diagrams for this project",
6545
+ "Create the location, streetview and climate sheets",
6546
+ "Add a climate diagram sheet to the presentation\n\n# Example\n```ts\nconst { sheetIds } = await snaptrude.presentation.diagrams.generateSite({\ntypes: [\"location\", \"climate\"],\n})\n```"
6547
+ ],
6548
+ "argsType": "{\n types?: PluginPresentationSiteDiagramType[]\n }",
6549
+ "resultType": "PluginPresentationDiagramsGenerateResult"
6550
+ },
5843
6551
  {
5844
6552
  "path": "presentation.diagrams.place",
5845
6553
  "namespace": "presentation.diagrams",
@@ -5905,6 +6613,316 @@
5905
6613
  "argsType": "{ url?: string; dataUrl?: string }",
5906
6614
  "resultType": "PluginPresentationImportResult"
5907
6615
  },
6616
+ {
6617
+ "path": "presentation.placedViews.deleteShapes",
6618
+ "namespace": "presentation.placedViews",
6619
+ "summary": "Delete Present-canvas shapes. One undoable step for the whole batch, and the batch is atomic — if any id is rejected, nothing is deleted.",
6620
+ "examplePrompts": [
6621
+ "Delete the old AI renders from the sheet",
6622
+ "Remove that placed view",
6623
+ "Clear the diagram images I placed\n\n# Example\n```ts\nconst { deleted } = await snaptrude.presentation.placedViews.deleteShapes([\nout1.shapeId,\nout2.shapeId,\n])\n```"
6624
+ ],
6625
+ "argsType": "string[]",
6626
+ "resultType": "PluginCanvasShapesDeleteResult"
6627
+ },
6628
+ {
6629
+ "path": "presentation.placedViews.get",
6630
+ "namespace": "presentation.placedViews",
6631
+ "summary": "Get a single placed view by its shape id.",
6632
+ "examplePrompts": [
6633
+ "Get the placed view I just dropped on the sheet",
6634
+ "Read the position and scale of this placed view",
6635
+ "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```"
6636
+ ],
6637
+ "argsType": "string",
6638
+ "resultType": "PluginPlacedView"
6639
+ },
6640
+ {
6641
+ "path": "presentation.placedViews.getShape",
6642
+ "namespace": "presentation.placedViews",
6643
+ "summary": "Get one Present-canvas shape by id — works for any top-level shape (placed view, AI output, diagram image, plugin shape, annotation), unlike `get` which requires a placed view. Requires Present mode to be open.",
6644
+ "examplePrompts": [
6645
+ "Inspect the AI render I just generated",
6646
+ "Get the bounds of that diagram image"
6647
+ ],
6648
+ "argsType": "string",
6649
+ "resultType": "PluginCanvasShape"
6650
+ },
6651
+ {
6652
+ "path": "presentation.placedViews.getStyles",
6653
+ "namespace": "presentation.placedViews",
6654
+ "summary": "Read a placed view's (or sheet's) per-category presentation styles.",
6655
+ "examplePrompts": [
6656
+ "What line weights is this placed plan using?",
6657
+ "Read the styling of the placed view",
6658
+ "Which categories can I restyle on this sheet?\n\n# Example\n```ts\nconst styles = await snaptrude.presentation.placedViews.getStyles(shapeId)\nconst space = styles.categories.find((c) => c.category === \"Space\")\nconsole.log(space?.settings.cutWidth, space?.settings.lineStyle)\n```"
6659
+ ],
6660
+ "argsType": "string",
6661
+ "resultType": "PluginPlacedViewStylesResult"
6662
+ },
6663
+ {
6664
+ "path": "presentation.placedViews.list",
6665
+ "namespace": "presentation.placedViews",
6666
+ "summary": "List the placed views in the presentation.",
6667
+ "examplePrompts": [
6668
+ "Which views are placed on this sheet?",
6669
+ "List all the placed views in the presentation",
6670
+ "What's laid out on sheet 2?",
6671
+ "Show me every view on the Present canvas\n\n# Example\n```ts\nconst { placedViews } = await snaptrude.presentation.placedViews.list(\"sheet_1\")\n```"
6672
+ ],
6673
+ "argsType": "string",
6674
+ "resultType": "PluginPresentationPlacedViewsListResult"
6675
+ },
6676
+ {
6677
+ "path": "presentation.placedViews.listLabels",
6678
+ "namespace": "presentation.placedViews",
6679
+ "summary": "List a placed view's labels — the text children generated from the view's content (space names, departments, areas, dimension texts). Each label is individually addressable: it can be moved and hidden. Returns `[]` when the view has no labels. Requires Present mode to be open.",
6680
+ "examplePrompts": [
6681
+ "List the labels on this placed plan",
6682
+ "Where are the space labels on this view?",
6683
+ "Show every label with its position\n\n# Example\n```ts\nconst { labels } = await snaptrude.presentation.placedViews.listLabels(shapeId)\nfor (const l of labels) console.log(l.text, l.position, l.hidden)\n```"
6684
+ ],
6685
+ "argsType": "string",
6686
+ "resultType": "PluginPlacedViewLabelsResult"
6687
+ },
6688
+ {
6689
+ "path": "presentation.placedViews.listShapes",
6690
+ "namespace": "presentation.placedViews",
6691
+ "summary": "List the top-level shapes on the Present canvas — not just placed views: AI-generated outputs, placed diagram images, plugin-created shapes, and annotations, each with an `origin` classification. Sheets (frames) are not listed — use `sheets.list`. Pass `sheetId` to list only shapes on that sheet. Returns `[]` when Present mode is closed.",
6692
+ "examplePrompts": [
6693
+ "List everything on the Present canvas",
6694
+ "What AI outputs are on this sheet?",
6695
+ "Show all the shapes with their positions\n\n# Example\n```ts\nconst { shapes } = await snaptrude.presentation.placedViews.listShapes()\nconst aiOutputs = shapes.filter((s) => s.origin === \"aiOutput\")\n```"
6696
+ ],
6697
+ "argsType": "string",
6698
+ "resultType": "PluginCanvasShapesListResult"
6699
+ },
6700
+ {
6701
+ "path": "presentation.placedViews.move",
6702
+ "namespace": "presentation.placedViews",
6703
+ "summary": "Move a placed view.",
6704
+ "examplePrompts": [
6705
+ "Move the site plan view to the top-left of sheet 2",
6706
+ "Reposition this placed view to 100, 200",
6707
+ "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```"
6708
+ ],
6709
+ "argsType": "string",
6710
+ "resultType": "PluginPlacedView"
6711
+ },
6712
+ {
6713
+ "path": "presentation.placedViews.moveLabel",
6714
+ "namespace": "presentation.placedViews",
6715
+ "summary": "Move a label to a new position (coordinates relative to its placed view, the same space `listLabels` reports). The manual position survives style changes. Undoable. Requires Present mode to be open.",
6716
+ "examplePrompts": [
6717
+ "Move the kitchen label out of the hatched area",
6718
+ "Nudge this label 20 units right",
6719
+ "Reposition the area text"
6720
+ ],
6721
+ "argsType": "string",
6722
+ "resultType": "PluginPlacedViewLabel"
6723
+ },
6724
+ {
6725
+ "path": "presentation.placedViews.moveShape",
6726
+ "namespace": "presentation.placedViews",
6727
+ "summary": "Move any Present-canvas shape (AI outputs, diagram images, plugin shapes, annotations — placed views too). Same coordinate semantics as `move`: sheet-local when on a sheet, page coordinates otherwise; pass `options.sheetId` to reparent onto a sheet. Undoable. Requires Present mode to be open.",
6728
+ "examplePrompts": [
6729
+ "Move the AI render to the top of the sheet",
6730
+ "Put the diagram image at 100, 200"
6731
+ ],
6732
+ "argsType": "string",
6733
+ "resultType": "PluginCanvasShape"
6734
+ },
6735
+ {
6736
+ "path": "presentation.placedViews.resetStyles",
6737
+ "namespace": "presentation.placedViews",
6738
+ "summary": "Reset a placed view's styling to defaults — the sidebar's Reset button: clears every per-category override and view-style restyle, resets font styles, and un-hides labels hidden by styling. Undoable. Requires Present mode to be open.",
6739
+ "examplePrompts": [
6740
+ "Reset this view's styling",
6741
+ "Clear all the style overrides on the placed plan",
6742
+ "Put the sheet styles back to default"
6743
+ ],
6744
+ "argsType": "string",
6745
+ "resultType": "void"
6746
+ },
6747
+ {
6748
+ "path": "presentation.placedViews.resizeShape",
6749
+ "namespace": "presentation.placedViews",
6750
+ "summary": "Resize any Present-canvas shape by a uniform factor about its top-left corner (aspect ratio held) — the generic counterpart of `scale`, which requires a placed view. Undoable. Requires Present mode to be open.",
6751
+ "examplePrompts": [
6752
+ "Make the AI output half its size",
6753
+ "Double the size of that image"
6754
+ ],
6755
+ "argsType": "string",
6756
+ "resultType": "PluginCanvasShape"
6757
+ },
6758
+ {
6759
+ "path": "presentation.placedViews.rotateShape",
6760
+ "namespace": "presentation.placedViews",
6761
+ "summary": "Rotate any Present-canvas shape (AI outputs, diagram images, plugin shapes, annotations — placed views too) — the generic counterpart of `setRotation`, same target rules as `moveShape`. Same semantics: **absolute** angle in radians (tldraw convention) about the shape's bounds center, canonicalized into `[0, 2π)` (pass values in that range for an exact round-trip via `getShape`), one undo step. A placed view passed here falls under the same 3D-only rule as `setRotation`: 2D and site-plan views cannot rotate and are refused with a typed `PRECONDITION_FAILED`. Requires Present mode to be open.",
6762
+ "examplePrompts": [
6763
+ "Rotate the AI render 15 degrees",
6764
+ "Turn that image sideways",
6765
+ "Reset the diagram image's rotation"
6766
+ ],
6767
+ "argsType": "string",
6768
+ "resultType": "PluginCanvasShape"
6769
+ },
6770
+ {
6771
+ "path": "presentation.placedViews.scale",
6772
+ "namespace": "presentation.placedViews",
6773
+ "summary": "Resize a placed view by a uniform factor.",
6774
+ "examplePrompts": [
6775
+ "Make this placed view twice as big",
6776
+ "Shrink the placed 3D view to half its size",
6777
+ "Scale the placed plan up by 50%\n\n# Example\n```ts\nawait snaptrude.presentation.placedViews.scale(shapeId, 2)\n```"
6778
+ ],
6779
+ "argsType": "string",
6780
+ "resultType": "PluginPlacedView"
6781
+ },
6782
+ {
6783
+ "path": "presentation.placedViews.setCrop",
6784
+ "namespace": "presentation.placedViews",
6785
+ "summary": "Crop a placed view, or clear its crop.",
6786
+ "examplePrompts": [
6787
+ "Crop the placed view to its left half",
6788
+ "Crop this view to the top-right quarter",
6789
+ "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```"
6790
+ ],
6791
+ "argsType": "string",
6792
+ "resultType": "PluginPlacedView"
6793
+ },
6794
+ {
6795
+ "path": "presentation.placedViews.setLabelHidden",
6796
+ "namespace": "presentation.placedViews",
6797
+ "summary": "Hide or show a single label (independent of the category-level label visibility). Undoable. Requires Present mode to be open.",
6798
+ "examplePrompts": [
6799
+ "Hide the corridor label",
6800
+ "Show that label again"
6801
+ ],
6802
+ "argsType": "string",
6803
+ "resultType": "PluginPlacedViewLabel"
6804
+ },
6805
+ {
6806
+ "path": "presentation.placedViews.setMask",
6807
+ "namespace": "presentation.placedViews",
6808
+ "summary": "Toggle \"mask context buildings\" on a placed view — mutes the inactive proposal buildings in the view (the sidebar checkbox). Views only. Undoable. Requires Present mode to be open.",
6809
+ "examplePrompts": [
6810
+ "Mask the context buildings in this view",
6811
+ "Show the neighboring proposals again in the placed view"
6812
+ ],
6813
+ "argsType": "string",
6814
+ "resultType": "void"
6815
+ },
6816
+ {
6817
+ "path": "presentation.placedViews.setOpacity",
6818
+ "namespace": "presentation.placedViews",
6819
+ "summary": "Set a Present-canvas shape's opacity (`0` transparent .. `1` opaque) — the sidebar's whole-shape opacity slider (distinct from the per-category fill opacity in `updateStyles`). Works for any top-level shape. Undoable. Requires Present mode to be open.",
6820
+ "examplePrompts": [
6821
+ "Fade the placed view to 50%",
6822
+ "Make the AI render semi-transparent"
6823
+ ],
6824
+ "argsType": "string",
6825
+ "resultType": "void"
6826
+ },
6827
+ {
6828
+ "path": "presentation.placedViews.setRotation",
6829
+ "namespace": "presentation.placedViews",
6830
+ "summary": "Set a placed view's rotation.",
6831
+ "examplePrompts": [
6832
+ "Rotate the placed plan 90 degrees",
6833
+ "Set this view's rotation to 45 degrees",
6834
+ "Straighten the placed view back to zero rotation\n\n# Example\n```ts\nawait snaptrude.presentation.placedViews.setRotation(shapeId, Math.PI / 2)\n```"
6835
+ ],
6836
+ "argsType": "string",
6837
+ "resultType": "PluginPlacedView"
6838
+ },
6839
+ {
6840
+ "path": "presentation.placedViews.setScale",
6841
+ "namespace": "presentation.placedViews",
6842
+ "summary": "Set a placed view's architectural scale.",
6843
+ "examplePrompts": [
6844
+ "Set the plan to 1:100",
6845
+ "Change the placed floor plan to 1:50 scale",
6846
+ "Make this view print at quarter-inch scale\n\n# Example\n```ts\nawait snaptrude.presentation.placedViews.setScale(shapeId, 100) // 1:100\n```"
6847
+ ],
6848
+ "argsType": "string",
6849
+ "resultType": "PluginPlacedView"
6850
+ },
6851
+ {
6852
+ "path": "presentation.placedViews.updateFontStyles",
6853
+ "namespace": "presentation.placedViews",
6854
+ "summary": "Update a category's label typography on a placed view (or sheet) — the configure panel's Text tab.",
6855
+ "examplePrompts": [
6856
+ "Set the space labels to Roboto 24px bold",
6857
+ "Hide the area values on this plan",
6858
+ "Make the department labels italic\n\n# Example\n```ts\nawait snaptrude.presentation.placedViews.updateFontStyles(shapeId, \"Space\", {\nobjectLabels: { fontFamily: \"Roboto\", fontWeight: \"700\", fontSize: 24 },\nvisibleTypes: [\"objectLabels\", \"areas\"],\n})\n```"
6859
+ ],
6860
+ "argsType": "string",
6861
+ "resultType": "void"
6862
+ },
6863
+ {
6864
+ "path": "presentation.placedViews.updateStyles",
6865
+ "namespace": "presentation.placedViews",
6866
+ "summary": "Update one style category on a placed view (or sheet) — the same writes the Present sidebar's per-category configure panel performs.",
6867
+ "examplePrompts": [
6868
+ "Set the Space cut line weight to 0.5 mm",
6869
+ "Make the Department lines dashed",
6870
+ "Color the plan by department",
6871
+ "Hide the dimension lines on this view",
6872
+ "Round the space corners with a 2 ft radius\n\n# Example\n```ts\nawait snaptrude.presentation.placedViews.updateStyles(shapeId, \"Space\", {\ncutWidth: 0.5,\nprojectionWidth: 0.18,\nlineStyle: \"dashed\",\ncolorMode: \"department\",\n})\n```"
6873
+ ],
6874
+ "argsType": "string",
6875
+ "resultType": "PluginPlacedViewCategoryStyles"
6876
+ },
6877
+ {
6878
+ "path": "presentation.shapes.list",
6879
+ "namespace": "presentation.shapes",
6880
+ "summary": "List the calling plugin's shapes.",
6881
+ "examplePrompts": [
6882
+ "Which annotations has my plugin placed on the sheets?",
6883
+ "List the plugin's shapes before refreshing them",
6884
+ "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```"
6885
+ ],
6886
+ "argsType": null,
6887
+ "resultType": "PluginPresentationShapesListResult"
6888
+ },
6889
+ {
6890
+ "path": "presentation.shapes.remove",
6891
+ "namespace": "presentation.shapes",
6892
+ "summary": "Delete the shape for a key.",
6893
+ "examplePrompts": [
6894
+ "Remove the FAR label from the sheet",
6895
+ "Delete the highlight the plugin added earlier",
6896
+ "Clear the \"far-label\" annotation\n\n# Example\n```ts\nconst removed = await snaptrude.presentation.shapes.remove(\"far-label\")\n```"
6897
+ ],
6898
+ "argsType": "string",
6899
+ "resultType": "boolean"
6900
+ },
6901
+ {
6902
+ "path": "presentation.shapes.removeAll",
6903
+ "namespace": "presentation.shapes",
6904
+ "summary": "Delete every shape owned by the calling plugin.",
6905
+ "examplePrompts": [
6906
+ "Clear all annotations my plugin added",
6907
+ "Reset the sheet output before rerunning the analysis",
6908
+ "Remove every plugin-drawn shape\n\n# Example\n```ts\nconst deleted = await snaptrude.presentation.shapes.removeAll()\n```"
6909
+ ],
6910
+ "argsType": null,
6911
+ "resultType": "number"
6912
+ },
6913
+ {
6914
+ "path": "presentation.shapes.upsert",
6915
+ "namespace": "presentation.shapes",
6916
+ "summary": "Create or update the shape for a key.",
6917
+ "examplePrompts": [
6918
+ "Update the analysis label on the sheet instead of adding another one",
6919
+ "Rerun the daylight report and refresh its annotations",
6920
+ "Keep one \"FAR: 2.4\" text on Sheet 1 that updates on each run",
6921
+ "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```"
6922
+ ],
6923
+ "argsType": "string",
6924
+ "resultType": "PluginPresentationShapesUpsertResult"
6925
+ },
5908
6926
  {
5909
6927
  "path": "presentation.sheets.create",
5910
6928
  "namespace": "presentation.sheets",
@@ -6005,6 +7023,18 @@
6005
7023
  "argsType": "string",
6006
7024
  "resultType": "PluginPresentationSheet"
6007
7025
  },
7026
+ {
7027
+ "path": "presentation.sheets.setMargin",
7028
+ "namespace": "presentation.sheets",
7029
+ "summary": "Set a sheet's print margin.",
7030
+ "examplePrompts": [
7031
+ "Set the sheet margin to half an inch",
7032
+ "Remove the margins on sheet_1",
7033
+ "Give the cover sheet a 10mm margin\n\n# Example\n```ts\nconst sheet = await snaptrude.presentation.sheets.setMargin(\"sheet_1\", 0.5)\n```"
7034
+ ],
7035
+ "argsType": "string",
7036
+ "resultType": "PluginPresentationSheet"
7037
+ },
6008
7038
  {
6009
7039
  "path": "presentation.sheets.setSize",
6010
7040
  "namespace": "presentation.sheets",
@@ -6030,6 +7060,56 @@
6030
7060
  "argsType": "{\n sheetId?: string\n }",
6031
7061
  "resultType": "PluginPresentationSheetsUpdatePlacedViewResult"
6032
7062
  },
7063
+ {
7064
+ "path": "presentation.slideshow.getState",
7065
+ "namespace": "presentation.slideshow",
7066
+ "summary": "Read the slideshow state.",
7067
+ "examplePrompts": [
7068
+ "Is the slideshow running?",
7069
+ "Which slide is the presentation on?",
7070
+ "Check the slideshow state\n\n# Example\n```ts\nconst { running, index } = await snaptrude.presentation.slideshow.getState()\n```"
7071
+ ],
7072
+ "argsType": null,
7073
+ "resultType": "PluginPresentationSlideshowState"
7074
+ },
7075
+ {
7076
+ "path": "presentation.slideshow.start",
7077
+ "namespace": "presentation.slideshow",
7078
+ "summary": "Start the slideshow.",
7079
+ "examplePrompts": [
7080
+ "Start the slideshow",
7081
+ "Present the sheets from the beginning",
7082
+ "Start the slideshow on sheet 3",
7083
+ "Play the presentation starting at the cover sheet\n\n# Example\n```ts\nconst state = await snaptrude.presentation.slideshow.start({ startIndex: 2 })\nconsole.log(state.running, state.index) // true, 2\n```"
7084
+ ],
7085
+ "argsType": "{\n sheetIds?: string[]\n startIndex?: number\n }",
7086
+ "resultType": "PluginPresentationSlideshowState"
7087
+ },
7088
+ {
7089
+ "path": "presentation.slideshow.stop",
7090
+ "namespace": "presentation.slideshow",
7091
+ "summary": "Stop the slideshow.",
7092
+ "examplePrompts": [
7093
+ "Stop the slideshow",
7094
+ "Exit the presentation",
7095
+ "Close the slideshow and go back to the sheets\n\n# Example\n```ts\nawait snaptrude.presentation.slideshow.stop()\n```"
7096
+ ],
7097
+ "argsType": null,
7098
+ "resultType": "PluginPresentationSlideshowState"
7099
+ },
7100
+ {
7101
+ "path": "presentation.tables.place",
7102
+ "namespace": "presentation.tables",
7103
+ "summary": "Place a table on a sheet.",
7104
+ "examplePrompts": [
7105
+ "Put the area schedule as a table on Sheet 1",
7106
+ "Add a table of the room programs to the cover sheet",
7107
+ "Paste this data as a table on the sheet",
7108
+ "Place a two-column table of space names and areas\n\n# Example\n```ts\nconst shape = await snaptrude.presentation.tables.place(\"sheet_1\", {\nrows: [\n[\"Room\", \"Area\"],\n[\"Kitchen\", \"12.4 m²\"],\n[\"Living\", \"28.0 m²\"],\n],\n}, { position: { x: 40, y: 40 } })\n```"
7109
+ ],
7110
+ "argsType": "string",
7111
+ "resultType": "PluginCanvasShape"
7112
+ },
6033
7113
  {
6034
7114
  "path": "presentation.views.capture",
6035
7115
  "namespace": "presentation.views",
@@ -6544,6 +7624,55 @@
6544
7624
  "argsType": null,
6545
7625
  "resultType": "PluginProgramSiteNorthAngleResult"
6546
7626
  },
7627
+ {
7628
+ "path": "program.site.getSiteAnalysis",
7629
+ "namespace": "program.site",
7630
+ "summary": "Read the persisted Site Analysis sheet for the active proposal.",
7631
+ "examplePrompts": [
7632
+ "Read the current Site Analysis sheet",
7633
+ "What zoning constraints are recorded for this proposal?\n\n# Example\n```ts\nconst analysis = await snaptrude.program.site.getSiteAnalysis()\nif (analysis) console.log(analysis.sheetName, analysis.rows)\n```"
7634
+ ],
7635
+ "argsType": null,
7636
+ "resultType": "PluginProgramSiteAnalysisResult"
7637
+ },
7638
+ {
7639
+ "path": "program.site.getTimezone",
7640
+ "namespace": "program.site",
7641
+ "summary": "Get the IANA timezone of the project's geographic location.",
7642
+ "examplePrompts": [
7643
+ "What timezone is this project in?",
7644
+ "Get the site's IANA timezone",
7645
+ "What's the local time zone at the project location?",
7646
+ "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```"
7647
+ ],
7648
+ "argsType": null,
7649
+ "resultType": "PluginProgramSiteTimezoneResult"
7650
+ },
7651
+ {
7652
+ "path": "program.site.getWeather",
7653
+ "namespace": "program.site",
7654
+ "summary": "Get the weather file resolved for the project site.",
7655
+ "examplePrompts": [
7656
+ "Which weather file is my project using?",
7657
+ "What EPW station was resolved for this site?",
7658
+ "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```"
7659
+ ],
7660
+ "argsType": null,
7661
+ "resultType": "PluginProgramSiteWeatherResult"
7662
+ },
7663
+ {
7664
+ "path": "program.site.listEdges",
7665
+ "namespace": "program.site",
7666
+ "summary": "List each site parcel's boundary edges with their front / side / rear classification — the same per-edge roles the buildable-envelope setback pills show on canvas, so a plugin can pick up the user's edge tagging without asking them to set it up again.",
7667
+ "examplePrompts": [
7668
+ "Which edge of my site is the front?",
7669
+ "Read the front / side / rear edges of the plot",
7670
+ "What setback applies to each site edge?",
7671
+ "Get the site edges the way the setback pills show them\n\n# Example\n```ts\nconst { sites } = await snaptrude.program.site.listEdges()\nfor (const site of sites)\nfor (const e of site.edges)\nconsole.log(e.edgeIndex, e.role, e.roleSource, e.setbackMeters)\n```"
7672
+ ],
7673
+ "argsType": null,
7674
+ "resultType": "PluginProgramSiteListEdgesResult"
7675
+ },
6547
7676
  {
6548
7677
  "path": "program.site.listGeoPolygons",
6549
7678
  "namespace": "program.site",
@@ -6570,6 +7699,17 @@
6570
7699
  "argsType": null,
6571
7700
  "resultType": "PluginProgramSiteListPolygonsResult"
6572
7701
  },
7702
+ {
7703
+ "path": "program.site.updateSiteAnalysis",
7704
+ "namespace": "program.site",
7705
+ "summary": "Merge sourced site/zoning constraints into the active proposal's persisted Site Analysis sheet.",
7706
+ "examplePrompts": [
7707
+ "Save these zoning constraints to Site Analysis",
7708
+ "Update the FAR and setbacks in the Site Analysis sheet\n\n# Example\n```ts\nconst result = await snaptrude.program.site.updateSiteAnalysis([\n{ category: \"FAR\", description: \"Floor Area Ratio\", quantity: 3.5, unit: \"ratio\" },\n{ category: \"Set backs\", description: \"Front setbacks\", quantity: 6, unit: \"m\" },\n])\nconsole.log(result.sheetName, result.updatedRows, result.appendedRows)\n```"
7709
+ ],
7710
+ "argsType": "PluginSiteAnalysisRow[]",
7711
+ "resultType": "PluginProgramSiteAnalysisUpdateResult"
7712
+ },
6573
7713
  {
6574
7714
  "path": "program.spreadsheet.addChart",
6575
7715
  "namespace": "program.spreadsheet",
@@ -6595,6 +7735,19 @@
6595
7735
  "argsType": "string",
6596
7736
  "resultType": "PluginProgramSpreadsheetAddConditionalFormattingResult"
6597
7737
  },
7738
+ {
7739
+ "path": "program.spreadsheet.addImage",
7740
+ "namespace": "program.spreadsheet",
7741
+ "summary": "Place a floating image on a workbook sheet from a base64 data URI.",
7742
+ "examplePrompts": [
7743
+ "Add my logo image to the report sheet",
7744
+ "Place a PNG at cell B2 on the Takeoff sheet",
7745
+ "Put an SVG diagram on a spreadsheet sheet",
7746
+ "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```"
7747
+ ],
7748
+ "argsType": "string",
7749
+ "resultType": "PluginProgramSpreadsheetAddImageResult"
7750
+ },
6598
7751
  {
6599
7752
  "path": "program.spreadsheet.bindings.create",
6600
7753
  "namespace": "program.spreadsheet.bindings",
@@ -6644,6 +7797,31 @@
6644
7797
  "argsType": "string",
6645
7798
  "resultType": "PluginProgramSpreadsheetCreateSheetResult"
6646
7799
  },
7800
+ {
7801
+ "path": "program.spreadsheet.datasets.list",
7802
+ "namespace": "program.spreadsheet.datasets",
7803
+ "summary": "List the stored plugin datasets.",
7804
+ "examplePrompts": [
7805
+ "List my plugin datasets",
7806
+ "What datasets are stored for the sheets?",
7807
+ "Show the data sets bindings can use\n\n# Example\n```ts\nconst { datasets } = await snaptrude.program.spreadsheet.datasets.list()\n```"
7808
+ ],
7809
+ "argsType": null,
7810
+ "resultType": "PluginProgramSpreadsheetDatasetsListResult"
7811
+ },
7812
+ {
7813
+ "path": "program.spreadsheet.datasets.set",
7814
+ "namespace": "program.spreadsheet.datasets",
7815
+ "summary": "Store (upsert) a named plugin dataset.",
7816
+ "examplePrompts": [
7817
+ "Store my plugin's rows as a named dataset",
7818
+ "Upload data the sheets can bind to and refresh",
7819
+ "Save a dataset for a live sheet binding",
7820
+ "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```"
7821
+ ],
7822
+ "argsType": "string",
7823
+ "resultType": "PluginProgramSpreadsheetDatasetsSetResult"
7824
+ },
6647
7825
  {
6648
7826
  "path": "program.spreadsheet.export",
6649
7827
  "namespace": "program.spreadsheet",
@@ -6912,5 +8090,127 @@
6912
8090
  ],
6913
8091
  "argsType": "PluginSpreadsheetTransactionOp[]",
6914
8092
  "resultType": "PluginProgramSpreadsheetTransactionResult"
8093
+ },
8094
+ {
8095
+ "path": "workspace.closePresentMode",
8096
+ "namespace": "workspace",
8097
+ "summary": "Close Present mode and return to the modeling canvas.",
8098
+ "examplePrompts": [
8099
+ "Close present mode",
8100
+ "Exit the presentation editor",
8101
+ "Go back to the modeling canvas\n\n# Example\n```ts\nawait snaptrude.workspace.closePresentMode()\n```"
8102
+ ],
8103
+ "argsType": null,
8104
+ "resultType": "void"
8105
+ },
8106
+ {
8107
+ "path": "workspace.openPresentMode",
8108
+ "namespace": "workspace",
8109
+ "summary": "Open Present mode — the documentation editor the `presentation.*` namespaces operate on.",
8110
+ "examplePrompts": [
8111
+ "Open present mode",
8112
+ "Switch to the presentation editor",
8113
+ "Open the sheets so I can lay out views\n\n# Example\n```ts\nawait snaptrude.workspace.openPresentMode()\nconst { sheets } = await snaptrude.presentation.sheets.list()\n```"
8114
+ ],
8115
+ "argsType": null,
8116
+ "resultType": "void"
8117
+ },
8118
+ {
8119
+ "path": "workspace.projects.copy",
8120
+ "namespace": "workspace.projects",
8121
+ "summary": "Copy the **current** project into a new project — the dashboard's \"Save As\".",
8122
+ "examplePrompts": [
8123
+ "Save this project as a new copy called Tower Study v2",
8124
+ "Duplicate the current project into the Acme team",
8125
+ "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```"
8126
+ ],
8127
+ "argsType": "string",
8128
+ "resultType": "PluginWorkspaceProjectsCopyResult"
8129
+ },
8130
+ {
8131
+ "path": "workspace.projects.create",
8132
+ "namespace": "workspace.projects",
8133
+ "summary": "Create a new, empty BIM project.",
8134
+ "examplePrompts": [
8135
+ "Create a new project called Tower Study",
8136
+ "Start a new project in the Acme team",
8137
+ "Make a fresh project using millimeters",
8138
+ "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```"
8139
+ ],
8140
+ "argsType": "string",
8141
+ "resultType": "PluginWorkspaceProjectsCreateResult"
8142
+ },
8143
+ {
8144
+ "path": "workspace.projects.get",
8145
+ "namespace": "workspace.projects",
8146
+ "summary": "Get a single project by id.",
8147
+ "examplePrompts": [
8148
+ "Get the project with this id",
8149
+ "Look up a project by its floorkey",
8150
+ "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```"
8151
+ ],
8152
+ "argsType": "string",
8153
+ "resultType": "PluginWorkspaceProjectsGetResult"
8154
+ },
8155
+ {
8156
+ "path": "workspace.projects.list",
8157
+ "namespace": "workspace.projects",
8158
+ "summary": "List the projects the user can access.",
8159
+ "examplePrompts": [
8160
+ "List all my projects",
8161
+ "Show the projects in the Acme team",
8162
+ "How many projects do I have?",
8163
+ "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```"
8164
+ ],
8165
+ "argsType": "{ teamId?: string }",
8166
+ "resultType": "PluginWorkspaceProjectsListResult"
8167
+ },
8168
+ {
8169
+ "path": "workspace.projects.rename",
8170
+ "namespace": "workspace.projects",
8171
+ "summary": "Rename a project.",
8172
+ "examplePrompts": [
8173
+ "Rename this project to Tower Study Final",
8174
+ "Change the name of project floorkey_123",
8175
+ "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```"
8176
+ ],
8177
+ "argsType": "string",
8178
+ "resultType": "PluginWorkspaceProjectsRenameResult"
8179
+ },
8180
+ {
8181
+ "path": "workspace.teams.get",
8182
+ "namespace": "workspace.teams",
8183
+ "summary": "Get a single team by id.",
8184
+ "examplePrompts": [
8185
+ "Get the team with id team_1",
8186
+ "Look up a team by its id",
8187
+ "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```"
8188
+ ],
8189
+ "argsType": "string",
8190
+ "resultType": "PluginWorkspaceTeamsGetResult"
8191
+ },
8192
+ {
8193
+ "path": "workspace.teams.list",
8194
+ "namespace": "workspace.teams",
8195
+ "summary": "List the teams the user belongs to.",
8196
+ "examplePrompts": [
8197
+ "List all my teams",
8198
+ "Which teams am I a member of?",
8199
+ "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```"
8200
+ ],
8201
+ "argsType": null,
8202
+ "resultType": "PluginWorkspaceTeamsListResult"
8203
+ },
8204
+ {
8205
+ "path": "workspace.teams.listMembers",
8206
+ "namespace": "workspace.teams",
8207
+ "summary": "List the members of a team.",
8208
+ "examplePrompts": [
8209
+ "List the members of the Acme team",
8210
+ "Who is on team_1?",
8211
+ "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```"
8212
+ ],
8213
+ "argsType": "string",
8214
+ "resultType": "PluginWorkspaceTeamsListMembersResult"
6915
8215
  }
6916
8216
  ]