@snaptrude/plugin-core 0.9.16 → 0.9.18-voids-20261016.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (107) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/api-manifest.full.json +10406 -0
  3. package/api-manifest.json +827 -51
  4. package/dist/api/analysis/daylight.d.ts +5 -5
  5. package/dist/api/analysis/solar.d.ts +2 -2
  6. package/dist/api/core/camera/index.d.ts +29 -0
  7. package/dist/api/core/camera/index.d.ts.map +1 -1
  8. package/dist/api/core/geom/create/index.d.ts +7 -1
  9. package/dist/api/core/geom/create/index.d.ts.map +1 -1
  10. package/dist/api/core/geom/update/contour.d.ts +8 -2
  11. package/dist/api/core/geom/update/contour.d.ts.map +1 -1
  12. package/dist/api/core/zoom/index.d.ts +13 -0
  13. package/dist/api/core/zoom/index.d.ts.map +1 -1
  14. package/dist/api/design/bim.d.ts +209 -0
  15. package/dist/api/design/bim.d.ts.map +1 -0
  16. package/dist/api/design/boolean/index.d.ts +2 -0
  17. package/dist/api/design/boolean/index.d.ts.map +1 -1
  18. package/dist/api/design/catalog.d.ts +320 -0
  19. package/dist/api/design/catalog.d.ts.map +1 -0
  20. package/dist/api/design/create/bulk-items.d.ts +65 -25
  21. package/dist/api/design/create/bulk-items.d.ts.map +1 -1
  22. package/dist/api/design/create/index.d.ts +272 -99
  23. package/dist/api/design/create/index.d.ts.map +1 -1
  24. package/dist/api/design/create/opening-fields.d.ts +13 -12
  25. package/dist/api/design/create/opening-fields.d.ts.map +1 -1
  26. package/dist/api/design/delete/index.d.ts +1 -0
  27. package/dist/api/design/delete/index.d.ts.map +1 -1
  28. package/dist/api/design/doors/index.d.ts +18 -24
  29. package/dist/api/design/doors/index.d.ts.map +1 -1
  30. package/dist/api/design/family.d.ts +797 -27
  31. package/dist/api/design/family.d.ts.map +1 -1
  32. package/dist/api/design/index.d.ts +16 -0
  33. package/dist/api/design/index.d.ts.map +1 -1
  34. package/dist/api/design/networks.d.ts +1703 -0
  35. package/dist/api/design/networks.d.ts.map +1 -0
  36. package/dist/api/design/query/index.d.ts +42 -32
  37. package/dist/api/design/query/index.d.ts.map +1 -1
  38. package/dist/api/design/selection/index.d.ts +10 -10
  39. package/dist/api/design/types/index.d.ts +40 -24
  40. package/dist/api/design/types/index.d.ts.map +1 -1
  41. package/dist/api/design/update/index.d.ts +43 -3
  42. package/dist/api/design/update/index.d.ts.map +1 -1
  43. package/dist/api/design/windows/index.d.ts +8 -8
  44. package/dist/api/design/windows/index.d.ts.map +1 -1
  45. package/dist/api/presentation/aiInspiration.d.ts +10 -10
  46. package/dist/api/presentation/annotate.d.ts +38 -22
  47. package/dist/api/presentation/annotate.d.ts.map +1 -1
  48. package/dist/api/presentation/drawingContract.d.ts +32 -0
  49. package/dist/api/presentation/drawingContract.d.ts.map +1 -0
  50. package/dist/api/presentation/drawings.d.ts +3523 -0
  51. package/dist/api/presentation/drawings.d.ts.map +1 -0
  52. package/dist/api/presentation/export.d.ts +23 -5
  53. package/dist/api/presentation/export.d.ts.map +1 -1
  54. package/dist/api/presentation/index.d.ts +41 -12
  55. package/dist/api/presentation/index.d.ts.map +1 -1
  56. package/dist/api/presentation/placedViews.d.ts +106 -6
  57. package/dist/api/presentation/placedViews.d.ts.map +1 -1
  58. package/dist/api/presentation/sections.d.ts +461 -0
  59. package/dist/api/presentation/sections.d.ts.map +1 -0
  60. package/dist/api/presentation/shapes.d.ts +2 -2
  61. package/dist/api/presentation/sheets.d.ts +175 -19
  62. package/dist/api/presentation/sheets.d.ts.map +1 -1
  63. package/dist/api/presentation/viewPresets.d.ts +222 -0
  64. package/dist/api/presentation/viewPresets.d.ts.map +1 -0
  65. package/dist/api/presentation/views.d.ts +103 -5
  66. package/dist/api/presentation/views.d.ts.map +1 -1
  67. package/dist/api/presentation/walkthroughs.d.ts +6 -6
  68. package/dist/errors/codes.d.ts +3 -1
  69. package/dist/errors/codes.d.ts.map +1 -1
  70. package/dist/index.cjs +3749 -2328
  71. package/dist/index.cjs.map +1 -1
  72. package/dist/index.js +3616 -2328
  73. package/dist/index.js.map +1 -1
  74. package/package.json +1 -1
  75. package/scripts/generate-manifest.mjs +5 -0
  76. package/src/api/core/camera/index.ts +29 -0
  77. package/src/api/core/geom/create/index.ts +7 -1
  78. package/src/api/core/geom/update/contour.ts +8 -2
  79. package/src/api/core/zoom/index.ts +13 -0
  80. package/src/api/design/bim.ts +121 -0
  81. package/src/api/design/boolean/index.ts +2 -0
  82. package/src/api/design/catalog.ts +203 -0
  83. package/src/api/design/create/bulk-items.ts +57 -17
  84. package/src/api/design/create/index.ts +288 -120
  85. package/src/api/design/create/opening-fields.ts +15 -12
  86. package/src/api/design/delete/index.ts +1 -0
  87. package/src/api/design/doors/index.ts +58 -42
  88. package/src/api/design/family.ts +662 -32
  89. package/src/api/design/index.ts +34 -4
  90. package/src/api/design/networks.ts +607 -0
  91. package/src/api/design/query/index.ts +12 -2
  92. package/src/api/design/types/index.ts +31 -24
  93. package/src/api/design/update/index.ts +44 -3
  94. package/src/api/design/windows/index.ts +40 -22
  95. package/src/api/presentation/annotate.ts +90 -58
  96. package/src/api/presentation/drawingContract.ts +70 -0
  97. package/src/api/presentation/drawings.ts +1179 -0
  98. package/src/api/presentation/export.ts +32 -6
  99. package/src/api/presentation/index.ts +48 -14
  100. package/src/api/presentation/placedViews.ts +119 -28
  101. package/src/api/presentation/sections.ts +420 -0
  102. package/src/api/presentation/sheets.ts +181 -20
  103. package/src/api/presentation/viewPresets.ts +241 -0
  104. package/src/api/presentation/views.ts +46 -6
  105. package/src/errors/codes.ts +7 -0
  106. package/test/drawingContract.test.mjs +288 -0
  107. package/test/errors.test.mjs +1 -0
package/api-manifest.json CHANGED
@@ -987,7 +987,7 @@
987
987
  "examplePrompts": [
988
988
  "Subtract the courtyard from the building mass",
989
989
  "Cut this solid out of that one",
990
- "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```"
990
+ "Subtract this box solid from that solid\n\n# Example\n```ts\n// buildingBrep minus courtyardBrep — order matters\nconst carved = await snaptrude.core.geom.create.brepFromSubtraction(buildingBrep, courtyardBrep)\n```"
991
991
  ],
992
992
  "argsType": "BrepHandle",
993
993
  "resultType": "BrepHandle"
@@ -2422,7 +2422,7 @@
2422
2422
  "summary": "Add a hole to a contour by appending an inner profile. Immutable — returns a NEW contour and leaves the input unchanged.",
2423
2423
  "examplePrompts": [
2424
2424
  "Cut a hole in this shape",
2425
- "Punch an opening through this floor outline\n\n# Example\n```ts\nconst outer = await snaptrude.core.geom.create.profileRect(10, 8)\nconst contour = await snaptrude.core.geom.create.contourFromProfile(outer)\nconst hole = await snaptrude.core.geom.create.profileRect(2, 2)\nconst withHole = await snaptrude.core.geom.update.contour.addHole(contour, hole)\nconst count = await snaptrude.core.geom.query.contour.getHoleCount(withHole) // 1\n```"
2425
+ "Punch an opening through this outline\n\n# Example\n```ts\nconst outer = await snaptrude.core.geom.create.profileRect(10, 8)\nconst contour = await snaptrude.core.geom.create.contourFromProfile(outer)\nconst hole = await snaptrude.core.geom.create.profileRect(2, 2)\nconst withHole = await snaptrude.core.geom.update.contour.addHole(contour, hole)\nconst count = await snaptrude.core.geom.query.contour.getHoleCount(withHole) // 1\n```"
2426
2426
  ],
2427
2427
  "argsType": "ContourHandle",
2428
2428
  "resultType": "ContourHandle"
@@ -2466,7 +2466,7 @@
2466
2466
  "summary": "Remove a hole from a contour by inner-profile index. Immutable — returns a NEW contour and leaves the input unchanged.",
2467
2467
  "examplePrompts": [
2468
2468
  "Remove the hole from this shape",
2469
- "Fill in the opening in this floor outline\n\n# Example\n```ts\nconst outer = await snaptrude.core.geom.create.profileRect(10, 8)\nconst hole = await snaptrude.core.geom.create.profileRect(2, 2)\nconst contour = await snaptrude.core.geom.create.contourFromProfiles(outer, [hole])\nconst solid = await snaptrude.core.geom.update.contour.removeHole(contour, 0)\n```"
2469
+ "Fill in the opening in this outline\n\n# Example\n```ts\nconst outer = await snaptrude.core.geom.create.profileRect(10, 8)\nconst hole = await snaptrude.core.geom.create.profileRect(2, 2)\nconst contour = await snaptrude.core.geom.create.contourFromProfiles(outer, [hole])\nconst solid = await snaptrude.core.geom.update.contour.removeHole(contour, 0)\n```"
2470
2470
  ],
2471
2471
  "argsType": "ContourHandle",
2472
2472
  "resultType": "ContourHandle"
@@ -4566,6 +4566,36 @@
4566
4566
  "resultType": "boolean",
4567
4567
  "deprecated": "core.camera.zoomSelection"
4568
4568
  },
4569
+ {
4570
+ "path": "design.bim.create",
4571
+ "namespace": "design.bim",
4572
+ "summary": "Execute native Sketch-to-BIM. Revalidates scope, catalogue access and construction before mutation. Uses native progress/cancel controls and worker cancellation. Floors/roofs retain project defaults.",
4573
+ "examplePrompts": [
4574
+ "Convert these sketch rooms to BIM with wall layers chosen for each room boundary"
4575
+ ],
4576
+ "argsType": "string",
4577
+ "resultType": "PluginBimResult"
4578
+ },
4579
+ {
4580
+ "path": "design.bim.getContext",
4581
+ "namespace": "design.bim",
4582
+ "summary": "Read room adjacency and native conversion eligibility in the active proposal.",
4583
+ "examplePrompts": [
4584
+ "Inspect the rooms on each side of these sketch wall boundaries"
4585
+ ],
4586
+ "argsType": "PluginBimContextArgs",
4587
+ "resultType": "PluginBimContext"
4588
+ },
4589
+ {
4590
+ "path": "design.bim.prepare",
4591
+ "namespace": "design.bim",
4592
+ "summary": "Stage a complete wall-construction assignment. A new prepare replaces this plugin's prior plan.",
4593
+ "examplePrompts": [
4594
+ "Validate wall layer assignments before converting sketch rooms to BIM"
4595
+ ],
4596
+ "argsType": "PluginBimPrepareArgs",
4597
+ "resultType": "PluginBimPreparation"
4598
+ },
4569
4599
  {
4570
4600
  "path": "design.boolean.intersect",
4571
4601
  "namespace": "design.boolean",
@@ -4607,6 +4637,38 @@
4607
4637
  "argsType": "ComponentHandle[]",
4608
4638
  "resultType": "BooleanOutcome"
4609
4639
  },
4640
+ {
4641
+ "path": "design.catalog.get",
4642
+ "namespace": "design.catalog",
4643
+ "summary": "",
4644
+ "examplePrompts": [],
4645
+ "argsType": "PluginCatalogReference",
4646
+ "resultType": "PluginCatalogEntry | null"
4647
+ },
4648
+ {
4649
+ "path": "design.catalog.list",
4650
+ "namespace": "design.catalog",
4651
+ "summary": "",
4652
+ "examplePrompts": [],
4653
+ "argsType": "PluginCatalogKind",
4654
+ "resultType": "PluginCatalogEntry[]"
4655
+ },
4656
+ {
4657
+ "path": "design.catalog.listCategories",
4658
+ "namespace": "design.catalog",
4659
+ "summary": "Discover categories from accessible saved families and current project constructions. Omit parent for roots; pass a slash-separated returned path for its direct children. This metadata read does not fetch recipes, include unsaved drafts or legacy mesh inventories, or establish capabilities. Use search then get before placement. Names retain their case.",
4660
+ "examplePrompts": [],
4661
+ "argsType": "PluginCatalogListCategoriesArgs",
4662
+ "resultType": "PluginCatalogCategory[]"
4663
+ },
4664
+ {
4665
+ "path": "design.catalog.search",
4666
+ "namespace": "design.catalog",
4667
+ "summary": "Search accessible saved-family and project-construction metadata without downloading recipes. Categories are data, not an SDK enum. Legacy mesh inventories and unsaved drafts are excluded. Inspect selected references with get before placement; a search match does not prove validity or supported behavior. Pagination reads live data, not a snapshot. Failures reject.",
4668
+ "examplePrompts": [],
4669
+ "argsType": "PluginCatalogSearchArgs",
4670
+ "resultType": "PluginCatalogSearchResult"
4671
+ },
4610
4672
  {
4611
4673
  "path": "design.create.beam",
4612
4674
  "namespace": "design.create",
@@ -4617,7 +4679,7 @@
4617
4679
  "Run a 300x600 beam across the room",
4618
4680
  "Extrude this cross-section into a 5m long beam\n\n# Example\n```ts\nconst rect = await snaptrude.core.geom.create.profileRect(0.3, 0.6)\nconst section = await snaptrude.core.geom.create.contourFromProfile(rect)\nconst alongX = await snaptrude.core.math.vec3.new(1, 0, 0)\nconst beam = await snaptrude.design.create.beam(section, 6, alongX)\n```"
4619
4681
  ],
4620
- "argsType": "ContourHandle",
4682
+ "argsType": "| [section: ContourHandle, length: number, direction?: Vec3Handle]\n | [axis: LineHandle, options: PluginFamilyPlacement]",
4621
4683
  "resultType": "ComponentHandle"
4622
4684
  },
4623
4685
  {
@@ -4643,7 +4705,7 @@
4643
4705
  "Put a dropped ceiling in the living room at 3 metres",
4644
4706
  "Add a 50mm thick ceiling lifted 2800mm from floor level\n\n# Example\n```ts\nconst rect = await snaptrude.core.geom.create.profileRect(5, 4)\nconst contour = await snaptrude.core.geom.create.contourFromProfile(rect)\nconst ceiling = await snaptrude.design.create.ceiling(contour, 0.05, 2.8)\n```"
4645
4707
  ],
4646
- "argsType": "ContourHandle",
4708
+ "argsType": "| [contour: ContourHandle, thickness: number, heightFromFloor?: number]\n | [contour: ContourHandle, options: PluginFamilyCeilingOptions]",
4647
4709
  "resultType": "ComponentHandle"
4648
4710
  },
4649
4711
  {
@@ -4656,7 +4718,7 @@
4656
4718
  "Create a 450mm square concrete column 4 metres high",
4657
4719
  "Stand a column up from this base point\n\n# Example\n```ts\nconst rect = await snaptrude.core.geom.create.profileRect(0.45, 0.45)\nconst crossSection = await snaptrude.core.geom.create.contourFromProfile(rect)\nconst base = await snaptrude.core.math.vec3.new(4, 0, 4)\nconst column = await snaptrude.design.create.column(base, crossSection, 3)\n```"
4658
4720
  ],
4659
- "argsType": "Vec3Handle",
4721
+ "argsType": "| [\n position: Vec3Handle,\n crossSection: ContourHandle,\n height: number,\n directionUp?: Vec3Handle,\n ]\n | [axis: LineHandle, options: PluginFamilyPlacement]",
4660
4722
  "resultType": "ComponentHandle"
4661
4723
  },
4662
4724
  {
@@ -4688,7 +4750,7 @@
4688
4750
  {
4689
4751
  "path": "design.create.door",
4690
4752
  "namespace": "design.create",
4691
- "summary": "Place a **door** from the catalog into a host wall.",
4753
+ "summary": "Place a parametric **door** family into a host wall.",
4692
4754
  "examplePrompts": [
4693
4755
  "Add a door to this wall here",
4694
4756
  "Place a sliding door on the selected wall",
@@ -4705,7 +4767,7 @@
4705
4767
  {
4706
4768
  "path": "design.create.doors",
4707
4769
  "namespace": "design.create",
4708
- "summary": "Place **many doors** into host walls in one undoable operation (bulk plural of {@linkcode door}). Each item carries its own catalog id, host wall, world position, and optional `facing`, `label`, `width` and `height` — the same fields as a `\"door\"` {@linkcode PluginDesignCreateOpeningOptions}. Validate-all-or-throw; one command.",
4770
+ "summary": "Place **many doors** into host walls in one undoable operation (bulk plural of {@linkcode door}). Each item carries its own family id, host wall, world position, and optional `facing`, `label`, `width` and `height` — the same fields as a `\"door\"` {@linkcode PluginDesignCreateOpeningOptions}. Validate-all-or-throw; one command.",
4709
4771
  "examplePrompts": [
4710
4772
  "Add doors to all of these walls at once",
4711
4773
  "Place a door in every room in one operation",
@@ -4715,7 +4777,7 @@
4715
4777
  ],
4716
4778
  "argsType": "PluginCreateDoorItem[]",
4717
4779
  "resultType": "ComponentHandle[]",
4718
- "performance": "Bulk creator — the whole batch is ONE host round-trip and ONE undo entry, and each distinct catalog source loads once. Always prefer this over calling `design.create.door` in a loop: build the full `items[]` array first (all host walls and points up front), then make one call. # Example ```ts const v = snaptrude.core.math.vec3 const [wall] = await snaptrude.design.query.listWalls({ isSelected: true }) const [entry] = await snaptrude.design.doors.listCatalog() const [front, side] = await snaptrude.design.create.doors([ { catalogId: entry.id, hostWall: wall, position: await v.new(2, 0, 5), label: \"D-01\" }, { catalogId: entry.id, hostWall: wall, position: await v.new(6, 0, 5), width: 1.2 }, ]) // `wall` was re-cut twice and no longer resolves — ask the opening for its host: const currentWall = await snaptrude.design.query.getHost(front) ```"
4780
+ "performance": "Bulk creator — the whole batch is ONE host round-trip and ONE undo entry. Always prefer this over calling `design.create.door` in a loop: build the full `items[]` array first (all host walls and points up front), then make one call. # Example ```ts const v = snaptrude.core.math.vec3 const [wall] = await snaptrude.design.query.listWalls({ isSelected: true }) const [entry] = await snaptrude.design.doors.listCatalog() const [front, side] = await snaptrude.design.create.doors([ { familyId: entry.id, hostWall: wall, position: await v.new(2, 0, 5), label: \"D-01\" }, { familyId: entry.id, hostWall: wall, position: await v.new(6, 0, 5), values: { width: \"1200mm\" } }, ]) // The host still resolves after both cuts: const currentWall = await snaptrude.design.query.getHost(front) ```"
4719
4781
  },
4720
4782
  {
4721
4783
  "path": "design.create.floor",
@@ -4727,9 +4789,9 @@
4727
4789
  "Lay flooring across the selected outline",
4728
4790
  "Put a floor at this position with 150mm thickness\n\n# Example\n```ts\nconst rect = await snaptrude.core.geom.create.profileRect(5, 4)\nconst contour = await snaptrude.core.geom.create.contourFromProfile(rect)\nconst floor = await snaptrude.design.create.floor(contour, 0.1)\n```"
4729
4791
  ],
4730
- "argsType": "ContourHandle",
4731
- "resultType": "ComponentHandle",
4732
- "performance": "For MORE THAN ONE floor, call `design.create.floors(items[])` — one host round-trip and ONE undo entry for the whole batch. Looping this single-floor creator is N round-trips and N undo entries."
4792
+ "argsType": "| [contour: ContourHandle, thickness: number, position?: Vec3Handle]\n | [contour: ContourHandle, options: PluginFamilyFloorOptions]",
4793
+ "resultType": "ComponentHandle[]",
4794
+ "performance": "For dimensional floors, `design.create.floors(items[])` uses one host round-trip and one undo entry. That bulk method does not accept native family options; use this method for a family-backed floor."
4733
4795
  },
4734
4796
  {
4735
4797
  "path": "design.create.floors",
@@ -4841,14 +4903,14 @@
4841
4903
  {
4842
4904
  "path": "design.create.opening",
4843
4905
  "namespace": "design.create",
4844
- "summary": "Place a catalog **door or window** into a host wall with optional size overrides.",
4906
+ "summary": "Place a parametric **door or window** into a host wall with parameter overrides.",
4845
4907
  "examplePrompts": [
4846
4908
  "Add a 1m wide door to this wall here",
4847
4909
  "Place a window with a 0.9m sill height on the selected wall"
4848
4910
  ],
4849
4911
  "argsType": "PluginDesignCreateOpeningOptions",
4850
4912
  "resultType": "ComponentHandle",
4851
- "performance": "Single-opening creator — use it for one hosted opening. For MORE THAN ONE, call `design.create.doors(items[])` / `design.create.windows(items[])`: the same per-item fields, one host round-trip, ONE undo entry. # 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, }) ```"
4913
+ "performance": "Single-opening creator — use it for one hosted opening. For MORE THAN ONE, call `design.create.doors(items[])` / `design.create.windows(items[])`: the same per-item fields, one host round-trip, ONE undo entry. # Example ```ts const opening = await snaptrude.design.create.opening({ kind: \"window\", familyId: windowType.id, hostWall: wall, position: await snaptrude.core.math.vec3.new(3, 0, 5), width: 1.2, height: 1.5, sillHeight: 0.9, }) ```"
4852
4914
  },
4853
4915
  {
4854
4916
  "path": "design.create.referenceLines",
@@ -4888,7 +4950,7 @@
4888
4950
  "Make a basement slab that extrudes downward",
4889
4951
  "Give this room outline a 6 inch slab\n\n# Example\n```ts\nconst rect = await snaptrude.core.geom.create.profileRect(12, 10)\nconst contour = await snaptrude.core.geom.create.contourFromProfile(rect)\nconst slab = await snaptrude.design.create.slab(contour, 0.15, \"down\", \"Plinth\")\n```"
4890
4952
  ],
4891
- "argsType": "ContourHandle",
4953
+ "argsType": "| [\n contour: ContourHandle,\n thickness: number,\n direction?: \"up\" | \"down\",\n slabType?: PluginSlabType,\n ]\n | [contour: ContourHandle, options: PluginFamilySlabOptions]",
4892
4954
  "resultType": "ComponentHandle"
4893
4955
  },
4894
4956
  {
@@ -4950,6 +5012,39 @@
4950
5012
  "argsType": "PluginStaircasePreset",
4951
5013
  "resultType": "ComponentHandle"
4952
5014
  },
5015
+ {
5016
+ "path": "design.create.void",
5017
+ "namespace": "design.create",
5018
+ "summary": "Cut a **void** — a hole, opening or shaft — through an existing FLAT slab, floor, roof or ceiling. The void is a selectable child object of its host (the \"Void\" of the Draw Void tool). It always cuts the full host thickness. It can be moved with `design.transform.move` (a move that would leave the host is shortened without a report) and removed with `design.delete.entities`; to resize, delete it and cut a new one (`design.update.space` refuses a void).",
5019
+ "examplePrompts": [
5020
+ "Cut a hole in this slab",
5021
+ "Add a 1.2m by 2.4m stair opening in the first-floor slab",
5022
+ "Make a 600 x 600 service penetration in the floor for the riser",
5023
+ "Put a skylight opening through the roof",
5024
+ "Cut a round 1m duct hole in the slab",
5025
+ "Make a cut-out in the ceiling for the light well",
5026
+ "Add a double-height atrium void in the level 2 floor"
5027
+ ],
5028
+ "argsType": "ComponentHandle",
5029
+ "resultType": "ComponentHandle",
5030
+ "performance": "Single-void creator. For MORE THAN ONE void, call `design.create.voids(items[])`: one host round-trip, ONE undo entry, one cut per host."
5031
+ },
5032
+ {
5033
+ "path": "design.create.voids",
5034
+ "namespace": "design.create",
5035
+ "summary": "Cut **many voids** (holes, openings, shafts) through slabs, floors, roofs and ceilings in one undoable operation (bulk plural of {@linkcode void}). Items may share a host or use different hosts — one shaft outline on every storey's slab AND floor is one call. Validate-all-or-throw: one item whose host does not contain the outline rejects the whole batch, so pass only the hosts that contain it; `details.itemIndex` names the failing item (for two overlapping items of the batch, the earlier one). At most 50 voids per host and 200 in all per call. Same outline rules as {@linkcode void}: plan outline, 25.4 mm (0.1 SU) clearance, floor AND slab are separate hosts. Call it as `snaptrude.design.create.voids(...)`.",
5036
+ "examplePrompts": [
5037
+ "Cut a lift shaft through every floor slab of the core",
5038
+ "Cut a 2m x 2m shaft through all the slabs at this location",
5039
+ "Make stair openings in all the floors above the staircases",
5040
+ "Make holes in the roof for these three skylights",
5041
+ "Cut openings in each storey's slab matching this outline",
5042
+ "Punch the same riser penetration through every floor at once"
5043
+ ],
5044
+ "argsType": "PluginCreateVoidItem[]",
5045
+ "resultType": "ComponentHandle[]",
5046
+ "performance": "ONE host round-trip, ONE undo entry, ONE cut per host. Never call `void` in a loop. Runs synchronously on the main thread: 50 voids on one host take about 1 s, and the time grows with the number of hosts (caps: 50 per host, 200 per call)."
5047
+ },
4953
5048
  {
4954
5049
  "path": "design.create.wallRuns",
4955
5050
  "namespace": "design.create",
@@ -4989,7 +5084,7 @@
4989
5084
  {
4990
5085
  "path": "design.create.window",
4991
5086
  "namespace": "design.create",
4992
- "summary": "Place a **window** from the catalog into a host wall.",
5087
+ "summary": "Place a parametric **window** family into a host wall.",
4993
5088
  "examplePrompts": [
4994
5089
  "Add a window to this wall here",
4995
5090
  "Place a casement window on the selected wall",
@@ -5005,7 +5100,7 @@
5005
5100
  {
5006
5101
  "path": "design.create.windows",
5007
5102
  "namespace": "design.create",
5008
- "summary": "Place **many windows** into host walls in one undoable operation (bulk plural of {@linkcode window}). Each item carries its own catalog id, host wall, world position, and optional `facing`, `label`, `width`, `height` and `sillHeight` — the same fields as a `\"window\"` {@linkcode PluginDesignCreateOpeningOptions}. `sillHeight` is measured from the host wall base to the BOTTOM of the window. Validate-all-or-throw; one command.",
5103
+ "summary": "Place **many windows** into host walls in one undoable operation (bulk plural of {@linkcode window}). Each item carries its own family id, host wall, world position, and optional `facing`, `label`, `width`, `height` and `sillHeight` — the same fields as a `\"window\"` {@linkcode PluginDesignCreateOpeningOptions}. `sillHeight` is measured from the host wall base to the BOTTOM of the window. Validate-all-or-throw; one command.",
5009
5104
  "examplePrompts": [
5010
5105
  "Add windows along this whole facade at once",
5011
5106
  "Place a window in every bedroom in one operation",
@@ -5015,7 +5110,7 @@
5015
5110
  ],
5016
5111
  "argsType": "PluginCreateWindowItem[]",
5017
5112
  "resultType": "ComponentHandle[]",
5018
- "performance": "Bulk creator — the whole batch is ONE host round-trip and ONE undo entry, and each distinct catalog source loads once. Always prefer this over calling `design.create.window` in a loop: build the full `items[]` array first (all host walls and points up front), then make one call. # Example ```ts const v = snaptrude.core.math.vec3 const [wall] = await snaptrude.design.query.listWalls({ isSelected: true }) const [casement] = await snaptrude.design.windows.listCatalog() const placed = await snaptrude.design.create.windows([ { catalogId: casement.id, hostWall: wall, position: await v.new(2, 0, 5), sillHeight: 0.9 }, { catalogId: casement.id, hostWall: wall, position: await v.new(5, 0, 5), sillHeight: 0.9 }, ]) const currentWall = await snaptrude.design.query.getHost(placed[0]) ```"
5113
+ "performance": "Bulk creator — the whole batch is ONE host round-trip and ONE undo entry. Always prefer this over calling `design.create.window` in a loop: build the full `items[]` array first (all host walls and points up front), then make one call. # Example ```ts const v = snaptrude.core.math.vec3 const [wall] = await snaptrude.design.query.listWalls({ isSelected: true }) const [casement] = await snaptrude.design.windows.listCatalog() const placed = await snaptrude.design.create.windows([ { familyId: casement.id, hostWall: wall, position: await v.new(2, 0, 5), values: { sill: \"900mm\" } }, { familyId: casement.id, hostWall: wall, position: await v.new(5, 0, 5), values: { sill: \"900mm\" } }, ]) const currentWall = await snaptrude.design.query.getHost(placed[0]) ```"
5019
5114
  },
5020
5115
  {
5021
5116
  "path": "design.delete.entities",
@@ -5026,7 +5121,8 @@
5026
5121
  "Remove these walls from the model",
5027
5122
  "Get rid of this mass entirely",
5028
5123
  "Delete all the furniture I picked",
5029
- "Remove the door and window I just created"
5124
+ "Remove the door and window I just created",
5125
+ "Remove the void I cut in this slab"
5030
5126
  ],
5031
5127
  "argsType": "ComponentHandle[]",
5032
5128
  "resultType": "PluginDesignChangeResult",
@@ -5137,7 +5233,7 @@
5137
5233
  {
5138
5234
  "path": "design.doors.getDimensions",
5139
5235
  "namespace": "design.doors",
5140
- "summary": "Get a door's full dimensions in one call — width along the wall, vertical height, and thickness through the wall — measured in the door's local oriented space. Parity with {@linkcode PluginDesignWindowsApi.getDimensions}.",
5236
+ "summary": "Get evaluated opening width/height and host thickness, in Snaptrude units. The opening can include allowances beyond the width/height input parameters.",
5141
5237
  "examplePrompts": [
5142
5238
  "What are the dimensions of this door?",
5143
5239
  "How big is the selected door?",
@@ -5176,7 +5272,7 @@
5176
5272
  {
5177
5273
  "path": "design.doors.getSupportFloor",
5178
5274
  "namespace": "design.doors",
5179
- "summary": "Get the floor a door is hosted on — the storey/level component that supports the door.",
5275
+ "summary": "Returns null for recipe doors. Room floors own doorway infill; there is no separate support-floor entity.",
5180
5276
  "examplePrompts": [
5181
5277
  "Which floor is this door on?",
5182
5278
  "What storey does the selected door belong to?",
@@ -5189,7 +5285,7 @@
5189
5285
  {
5190
5286
  "path": "design.doors.getSwingDirection",
5191
5287
  "namespace": "design.doors",
5192
- "summary": "Get a door's swing (hinge) handedness. Stand on the side the door swings open to, facing the door: `'left'` when the hinged jamb is on your left, `'right'` when it is on your right. Derived from the placed mesh's orientation (the same reflection `mirror` and the `hinge` placement option apply), not a persisted field.",
5288
+ "summary": "Read the saved hand parameter. left means local -X; right means local +X. Returns null when the recipe does not declare that control.",
5193
5289
  "examplePrompts": [
5194
5290
  "Which way does this door swing?",
5195
5291
  "Is the selected door left-handed or right-handed?",
@@ -5254,7 +5350,7 @@
5254
5350
  {
5255
5351
  "path": "design.doors.mirror",
5256
5352
  "namespace": "design.doors",
5257
- "summary": "Mirror a door about its own axes. `'x'` (default) flips the swing side — the door opens to the other side of the wall; `'z'` swaps the hinged jamb (left-hand ↔ right-hand, same swing side); `'y'` turns it upside down. Undoable as a single command.",
5353
+ "summary": "Change authored controls in one undo step: x (default) toggles swing front/back; z toggles hand left/right. The recipe must declare these enums. Axis y rejects. No mesh reflection occurs. Recipes use outputs.swingSide (1 or -1) for the adjoining room's floor ownership. A door between two room floors requires this output; a missing or invalid report rejects the cut.",
5258
5354
  "examplePrompts": [
5259
5355
  "Flip this door's swing",
5260
5356
  "Mirror the selected door",
@@ -5305,6 +5401,46 @@
5305
5401
  "argsType": "ComponentHandle",
5306
5402
  "resultType": "OffsetSplitOutcome"
5307
5403
  },
5404
+ {
5405
+ "path": "design.electrical.context",
5406
+ "namespace": "design.electrical",
5407
+ "summary": "Read the active proposal's architectural context before authoring. Keep one revision across pages.",
5408
+ "examplePrompts": [],
5409
+ "argsType": "z.input<typeof NetworkContextArgs>",
5410
+ "resultType": "NetworkContextResult"
5411
+ },
5412
+ {
5413
+ "path": "design.electrical.create",
5414
+ "namespace": "design.electrical",
5415
+ "summary": "Construct each node on its authored storey, with one undo command and queued project persistence. Networks can span storeys. Reuse requestId on retry; components returns the durable node mapping. Coordinates are world millimetres, Y-up; rotations are degrees. No engineering rules are inferred. Throws for stale architecture, invalid references/geometry or conflicting retries.",
5416
+ "examplePrompts": [],
5417
+ "argsType": "z.input<typeof NetworkCreateArgs>",
5418
+ "resultType": "NetworkCreateResult"
5419
+ },
5420
+ {
5421
+ "path": "design.electrical.get",
5422
+ "namespace": "design.electrical",
5423
+ "summary": "Read one saved graph in the active proposal; null on miss. IDs are durable, not worker handles.",
5424
+ "examplePrompts": [],
5425
+ "argsType": "z.input<typeof NetworkGetArgs>",
5426
+ "resultType": "SavedNetworkGraph | null"
5427
+ },
5428
+ {
5429
+ "path": "design.electrical.query",
5430
+ "namespace": "design.electrical",
5431
+ "summary": "Read bounded authored topology in graph revision. Crossings do not connect. No clash/compliance claims.",
5432
+ "examplePrompts": [],
5433
+ "argsType": "z.input<typeof NetworkQueryArgs>",
5434
+ "resultType": "NetworkQueryResult"
5435
+ },
5436
+ {
5437
+ "path": "design.electrical.validate",
5438
+ "namespace": "design.electrical",
5439
+ "summary": "Validate authored JSON, pinned families and recipe evaluation without placing or saving anything. This does not build kernel meshes or certify engineering/code compliance.",
5440
+ "examplePrompts": [],
5441
+ "argsType": "z.input<typeof NetworkValidateArgs>",
5442
+ "resultType": "NetworkValidation"
5443
+ },
5308
5444
  {
5309
5445
  "path": "design.erase.edge",
5310
5446
  "namespace": "design.erase",
@@ -5335,7 +5471,7 @@
5335
5471
  {
5336
5472
  "path": "design.family.create",
5337
5473
  "namespace": "design.family",
5338
- "summary": "Save the prepared bundle to the library — the user's personal library unless `teamId` is given. {@linkcode PluginDesignFamilyApi.place} already saves, so `create` is for sharing with a team. When nothing of the family is in the model yet, one instance is also dropped at the centre of the current view on the active storey (`placed: true`), so a save is never invisible.",
5474
+ "summary": "Save the prepared bundle to the library — the user's personal library unless `teamId` is given. {@linkcode PluginDesignFamilyApi.place} already saves generic components. Hosted doors/windows save without placement; they need a wall and position through `design.create.door` / `design.create.window`. For a non-hosted family with no placed instance, saving also drops one standalone sample at the current view centre on the active storey (`placed: true`). This includes architectural families: the sample does not assign a family to a native host.",
5339
5475
  "examplePrompts": [
5340
5476
  "Save this as a family called Vertical Louvre",
5341
5477
  "Add it to my library\n\n# Example\n```ts\nconst { definitionId } = await snaptrude.design.family.create({ name: \"Louvre Screen\" })\n```"
@@ -5351,7 +5487,7 @@
5351
5487
  "Delete the Louvre Screen family from my library",
5352
5488
  "Get rid of that bollard and every copy of it in here\n\n# Example\n```ts\nawait snaptrude.design.family.delete({ id: \"revit:steel-bollard~bef047\" })\nawait snaptrude.design.family.delete({ id: \"revit:steel-bollard~bef047\", instances: true })\n```"
5353
5489
  ],
5354
- "argsType": "PluginDesignFamilyDeleteArgs",
5490
+ "argsType": "PluginDesignFamilyDeleteArgs | string",
5355
5491
  "resultType": "PluginFamilyDeleteResult"
5356
5492
  },
5357
5493
  {
@@ -5368,10 +5504,32 @@
5368
5504
  {
5369
5505
  "path": "design.family.get",
5370
5506
  "namespace": "design.family",
5371
- "summary": "The prepared family's spec bundle, or `null` when nothing is prepared.",
5507
+ "summary": "A family's spec bundle: the prepared draft's, or — to CHANGE a saved family — that family's recipe, opened as the new draft.",
5508
+ "examplePrompts": [
5509
+ "Make the chairs I placed 50 mm wider",
5510
+ "Change the Louvre Screen family so its blades are deeper\n\n# Example\n```ts\nconst draft = await snaptrude.design.family.get()\nconst family = await snaptrude.design.family.get({ component })\n// family.editing → { familyId, version, name, library }\n```"
5511
+ ],
5512
+ "argsType": "PluginDesignFamilyGetArgs | string",
5513
+ "resultType": "PluginFamilyGetResult | null"
5514
+ },
5515
+ {
5516
+ "path": "design.family.getDefinition",
5517
+ "namespace": "design.family",
5518
+ "summary": "Read one saved catalog definition without opening a draft or placing geometry. Both id and version are required. The catalog checks access on every read. Length defaults and bounds are in mm, ready for network graph overrides; angle parameters retain degrees, identified by each parameter's unit. existing getParameters/place/setParameters continue to use Snaptrude units. Defaults include current catalog overrides, which can change without a new version. No scene, registry, history, or persistence state is changed. Missing/inaccessible pins and invalid recipes fail; no latest-version fallback. This metadata does not certify connectors or engineering compatibility.",
5372
5519
  "examplePrompts": [],
5373
- "argsType": null,
5374
- "resultType": "PluginFamilyBundle | null"
5520
+ "argsType": "PluginDesignFamilyGetDefinitionArgs",
5521
+ "resultType": "PluginFamilyDefinition"
5522
+ },
5523
+ {
5524
+ "path": "design.family.getExamples",
5525
+ "namespace": "design.family",
5526
+ "summary": "Worked example families to learn from: real, tested bundles by discipline (architecture, structure, MEP, furniture). With no `id`, returns the catalogue — each example's id, label, discipline and the patterns it teaches — filtered by `discipline` / `tag` when given. With an `id`, returns that example's full bundle. Fetch the one closest to the task before authoring and borrow its patterns; examples are patterns to combine, not templates to copy whole.",
5527
+ "examplePrompts": [
5528
+ "Show me an example of a structural family",
5529
+ "How is a hosted door family written?\n\n# Example\n```ts\nconst list = await snaptrude.design.family.getExamples({ discipline: \"mep\" })\nconst ex = await snaptrude.design.family.getExamples({ id: list[0].id })\n```"
5530
+ ],
5531
+ "argsType": "PluginDesignFamilyGetExamplesArgs | string",
5532
+ "resultType": "PluginFamilyExampleSummary[] | PluginFamilyExample"
5375
5533
  },
5376
5534
  {
5377
5535
  "path": "design.family.getParameters",
@@ -5392,19 +5550,43 @@
5392
5550
  "How do I write a parametric family spec?",
5393
5551
  "Show me the family DSL\n\n# Example\n```ts\nconst { reference } = await snaptrude.design.family.getReference()\n```"
5394
5552
  ],
5395
- "argsType": null,
5553
+ "argsType": "PluginDesignFamilyGetReferenceArgs | PluginFamilyReferenceSection",
5396
5554
  "resultType": "PluginFamilyReference"
5397
5555
  },
5556
+ {
5557
+ "path": "design.family.getTemplate",
5558
+ "namespace": "design.family",
5559
+ "summary": "Get a validated starter recipe for a door or window, with an opening contract, host wall-thickness binding and role-named parts. Edit profiles, panels, glazing, hardware and materials while preserving the contract. Use `prepare` / `flex` to check the recipe, then `create` to save it and `design.create.door(familyId, hostWall, position, { version, values }, facing)` (or `window`) to place it. Edit the resulting ParametricComponent through `getParameters` / `setParameters`, not a separate opening API.",
5560
+ "examplePrompts": [],
5561
+ "argsType": "PluginDesignFamilyGetTemplateArgs",
5562
+ "resultType": "PluginFamilyTemplateResult"
5563
+ },
5398
5564
  {
5399
5565
  "path": "design.family.list",
5400
5566
  "namespace": "design.family",
5401
- "summary": "Every parametric family registered in this session — native and imported.",
5567
+ "summary": "Every available parametric family, merging the session registry and catalog.",
5402
5568
  "examplePrompts": [
5403
5569
  "What families are available?\n\n# Example\n```ts\nconst families = await snaptrude.design.family.list()\n```"
5404
5570
  ],
5405
- "argsType": null,
5571
+ "argsType": "PluginDesignFamilyListArgs & { compact: true }",
5572
+ "resultType": "string[]"
5573
+ },
5574
+ {
5575
+ "path": "design.family.list",
5576
+ "namespace": "design.family",
5577
+ "summary": "",
5578
+ "examplePrompts": [],
5579
+ "argsType": "PluginDesignFamilyListArgs & { compact?: false }",
5406
5580
  "resultType": "PluginFamilySummary[]"
5407
5581
  },
5582
+ {
5583
+ "path": "design.family.list",
5584
+ "namespace": "design.family",
5585
+ "summary": "",
5586
+ "examplePrompts": [],
5587
+ "argsType": "PluginDesignFamilyListArgs",
5588
+ "resultType": "PluginFamilySummary[] | string[]"
5589
+ },
5408
5590
  {
5409
5591
  "path": "design.family.place",
5410
5592
  "namespace": "design.family",
@@ -5412,7 +5594,7 @@
5412
5594
  "examplePrompts": [
5413
5595
  "Place it in the model",
5414
5596
  "Put a louvre screen at the origin",
5415
- "Copy that table two metres to the right\n\n# Example\n```ts\n// positioned — geometry exists when this resolves\nconst { component } = await snaptrude.design.family.place({\nid: \"revit:gypsum-stud-partition~90ad72\",\nposition: { x: 0, y: 0, z: 0 },\nrotation: 90,\n})\nawait snaptrude.design.transform.move([component], { x: 2, y: 0, z: 0 })\n\n// interactive — the user clicks\nawait snaptrude.design.family.place()\n```"
5597
+ "Copy that table two metres to the right\n\n# Example\n```ts\n// positioned — geometry exists when this resolves\nconst { component } = await snaptrude.design.family.place({\nid: \"revit:gypsum-stud-partition~90ad72\",\nposition: { x: 0, y: 0, z: 0 },\nrotation: 90,\n})\nawait snaptrude.design.transform.move([component], { x: 2, y: 0, z: 0 })\n\n// interactive — the user clicks\nawait snaptrude.design.family.place()\n\n// hosted — a door in a wall, near a point along it\nawait snaptrude.design.family.place({ id: doorId, host: wall, position: { x: 3, y: 0, z: 0 } })\n```"
5416
5598
  ],
5417
5599
  "argsType": "PluginDesignFamilyPlaceArgs",
5418
5600
  "resultType": "PluginFamilyPlaceResult"
@@ -5436,7 +5618,7 @@
5436
5618
  "summary": "Change a placed component's parameters and rebuild its geometry in place.",
5437
5619
  "examplePrompts": [
5438
5620
  "Make that table seat 8",
5439
- "Change the stud spacing to 400\n\n# Example\n```ts\nawait snaptrude.design.family.setParameters({ component, values: { seats: 8 } })\n```"
5621
+ "Change the stud spacing to 400\n\n# Example\n```ts\nawait snaptrude.design.family.setParameters({ component, values: { seats: 8 } })\nawait snaptrude.design.family.setParameters({ component, children: { chair: { width: \"380mm\" } } })\nawait snaptrude.design.family.setParameters({\ncomponent: railing,\nlinks: { steps: { from: stair, expr: \"steps\" }, side: { from: stair, expr: \"width - 40mm\" } },\n})\nawait snaptrude.design.family.setParameters({\ncomponent: post,\nrelations: { add: [{ kind: \"attach\", side: \"top\", to: slab, bind: { height: \"reach\" } }] },\n})\n```"
5440
5622
  ],
5441
5623
  "argsType": "PluginDesignFamilySetParametersArgs",
5442
5624
  "resultType": "PluginFamilyInstanceParameters"
@@ -5847,6 +6029,86 @@
5847
6029
  "argsType": "ComponentHandle",
5848
6030
  "resultType": "PluginMaterialResult"
5849
6031
  },
6032
+ {
6033
+ "path": "design.mechanical.context",
6034
+ "namespace": "design.mechanical",
6035
+ "summary": "Read the active proposal's architectural context before authoring. Keep one revision across pages.",
6036
+ "examplePrompts": [],
6037
+ "argsType": "z.input<typeof NetworkContextArgs>",
6038
+ "resultType": "NetworkContextResult"
6039
+ },
6040
+ {
6041
+ "path": "design.mechanical.create",
6042
+ "namespace": "design.mechanical",
6043
+ "summary": "Construct each node on its authored storey, with one undo command and queued project persistence. Networks can span storeys. Reuse requestId on retry; components returns the durable node mapping. Coordinates are world millimetres, Y-up; rotations are degrees. No engineering rules are inferred. Throws for stale architecture, invalid references/geometry or conflicting retries.",
6044
+ "examplePrompts": [],
6045
+ "argsType": "z.input<typeof NetworkCreateArgs>",
6046
+ "resultType": "NetworkCreateResult"
6047
+ },
6048
+ {
6049
+ "path": "design.mechanical.get",
6050
+ "namespace": "design.mechanical",
6051
+ "summary": "Read one saved graph in the active proposal; null on miss. IDs are durable, not worker handles.",
6052
+ "examplePrompts": [],
6053
+ "argsType": "z.input<typeof NetworkGetArgs>",
6054
+ "resultType": "SavedNetworkGraph | null"
6055
+ },
6056
+ {
6057
+ "path": "design.mechanical.query",
6058
+ "namespace": "design.mechanical",
6059
+ "summary": "Read bounded authored topology in graph revision. Crossings do not connect. No clash/compliance claims.",
6060
+ "examplePrompts": [],
6061
+ "argsType": "z.input<typeof NetworkQueryArgs>",
6062
+ "resultType": "NetworkQueryResult"
6063
+ },
6064
+ {
6065
+ "path": "design.mechanical.validate",
6066
+ "namespace": "design.mechanical",
6067
+ "summary": "Validate authored JSON, pinned families and recipe evaluation without placing or saving anything. This does not build kernel meshes or certify engineering/code compliance.",
6068
+ "examplePrompts": [],
6069
+ "argsType": "z.input<typeof NetworkValidateArgs>",
6070
+ "resultType": "NetworkValidation"
6071
+ },
6072
+ {
6073
+ "path": "design.plumbing.context",
6074
+ "namespace": "design.plumbing",
6075
+ "summary": "Read the active proposal's architectural context before authoring. Keep one revision across pages.",
6076
+ "examplePrompts": [],
6077
+ "argsType": "z.input<typeof NetworkContextArgs>",
6078
+ "resultType": "NetworkContextResult"
6079
+ },
6080
+ {
6081
+ "path": "design.plumbing.create",
6082
+ "namespace": "design.plumbing",
6083
+ "summary": "Construct each node on its authored storey, with one undo command and queued project persistence. Networks can span storeys. Reuse requestId on retry; components returns the durable node mapping. Coordinates are world millimetres, Y-up; rotations are degrees. No engineering rules are inferred. Throws for stale architecture, invalid references/geometry or conflicting retries.",
6084
+ "examplePrompts": [],
6085
+ "argsType": "z.input<typeof NetworkCreateArgs>",
6086
+ "resultType": "NetworkCreateResult"
6087
+ },
6088
+ {
6089
+ "path": "design.plumbing.get",
6090
+ "namespace": "design.plumbing",
6091
+ "summary": "Read one saved graph in the active proposal; null on miss. IDs are durable, not worker handles.",
6092
+ "examplePrompts": [],
6093
+ "argsType": "z.input<typeof NetworkGetArgs>",
6094
+ "resultType": "SavedNetworkGraph | null"
6095
+ },
6096
+ {
6097
+ "path": "design.plumbing.query",
6098
+ "namespace": "design.plumbing",
6099
+ "summary": "Read bounded authored topology in graph revision. Crossings do not connect. No clash/compliance claims.",
6100
+ "examplePrompts": [],
6101
+ "argsType": "z.input<typeof NetworkQueryArgs>",
6102
+ "resultType": "NetworkQueryResult"
6103
+ },
6104
+ {
6105
+ "path": "design.plumbing.validate",
6106
+ "namespace": "design.plumbing",
6107
+ "summary": "Validate authored JSON, pinned families and recipe evaluation without placing or saving anything. This does not build kernel meshes or certify engineering/code compliance.",
6108
+ "examplePrompts": [],
6109
+ "argsType": "z.input<typeof NetworkValidateArgs>",
6110
+ "resultType": "NetworkValidation"
6111
+ },
5850
6112
  {
5851
6113
  "path": "design.query.exists",
5852
6114
  "namespace": "design.query",
@@ -5969,12 +6231,13 @@
5969
6231
  {
5970
6232
  "path": "design.query.getHost",
5971
6233
  "namespace": "design.query",
5972
- "summary": "Get an entity's host/parent entity (e.g. the wall a door is cut into).",
6234
+ "summary": "Get an entity's host/parent entity (e.g. the wall a door is cut into, or the slab, floor, roof or ceiling a void is cut through).",
5973
6235
  "examplePrompts": [
5974
6236
  "Which wall is this door in?",
5975
6237
  "Find the parent of the selected window",
5976
6238
  "What is this element attached to?",
5977
- "Which wall hosts this window?\n\n# Example\n```ts\n// From a door up to its host wall, then measure the wall\nconst [door] = await snaptrude.design.query.listDoors({ isSelected: true })\nconst hostWall = door ? await snaptrude.design.query.getHost(door) : null\nif (hostWall) {\nconst m = await snaptrude.design.query.measure(hostWall)\nconsole.log(\"wall length:\", m?.length)\n}\n```"
6239
+ "Which wall hosts this window?",
6240
+ "Which slab is this shaft in?\n\n# Example\n```ts\n// From a door up to its host wall, then measure the wall\nconst [door] = await snaptrude.design.query.listDoors({ isSelected: true })\nconst hostWall = door ? await snaptrude.design.query.getHost(door) : null\nif (hostWall) {\nconst m = await snaptrude.design.query.measure(hostWall)\nconsole.log(\"wall length:\", m?.length)\n}\n```"
5978
6241
  ],
5979
6242
  "argsType": "ComponentHandle",
5980
6243
  "resultType": "ComponentHandle | null"
@@ -6088,12 +6351,13 @@
6088
6351
  {
6089
6352
  "path": "design.query.listChildren",
6090
6353
  "namespace": "design.query",
6091
- "summary": "List an entity's direct child entities — for example the doors and windows hosted in a wall.",
6354
+ "summary": "List an entity's direct child entities — for example the doors and windows hosted in a wall, or the voids (holes, shafts, openings) cut in a slab, floor, roof or ceiling by `design.create.void`.",
6092
6355
  "examplePrompts": [
6093
6356
  "What's inside this wall — list its doors and windows",
6094
6357
  "Show the child elements of the selected object",
6095
6358
  "Which openings belong to this wall?",
6096
- "List everything nested under this mass\n\n# Example\n```ts\n// Count the openings hosted in a wall, split by kind\nconst children = await snaptrude.design.query.listChildren(wall)\nlet doors = 0\nlet windows = 0\nfor (const child of children) {\nconst kind = await snaptrude.design.query.getEntityType(child)\nif (kind === \"door\") doors++\nif (kind === \"window\") windows++\n}\n```"
6359
+ "List everything nested under this mass",
6360
+ "List all holes in this slab\n\n# Example\n```ts\n// Count the openings hosted in a wall, split by kind\nconst children = await snaptrude.design.query.listChildren(wall)\nlet doors = 0\nlet windows = 0\nfor (const child of children) {\nconst kind = await snaptrude.design.query.getEntityType(child)\nif (kind === \"door\") doors++\nif (kind === \"window\") windows++\n}\n```"
6097
6361
  ],
6098
6362
  "argsType": "ComponentHandle",
6099
6363
  "resultType": "ComponentHandle[]"
@@ -6522,14 +6786,14 @@
6522
6786
  {
6523
6787
  "path": "design.types.get",
6524
6788
  "namespace": "design.types",
6525
- "summary": "Get one building type by its `\"<kind>:<name>\"` id — its labelled layer stack (each layer's role, thickness and material) plus the summed total thickness.",
6789
+ "summary": "Get one building type by its legacy id or exact native wall pin — its labelled layer stack (each layer's role, thickness and material) plus the summed total thickness.",
6526
6790
  "examplePrompts": [
6527
6791
  "What layers make up this wall type?",
6528
6792
  "Show the construction of the exposed-concrete wall",
6529
6793
  "What's the total thickness of this slab type?",
6530
- "Which materials are in this roof assembly?\n\n# Example\n```ts\nconst [first] = await snaptrude.design.types.list(\"wall\")\nconst type = await snaptrude.design.types.get(first.id)\nif (type) for (const layer of type.layers) console.log(layer.name, layer.thickness)\n```"
6794
+ "Which materials are in this roof assembly?\n\n# Example\n```ts\nconst [first] = await snaptrude.design.types.list(\"wall\")\nconst type = await snaptrude.design.types.get(first.nativeFamily ?? first.id)\nif (type) for (const layer of type.layers) console.log(layer.name, layer.thickness)\n```"
6531
6795
  ],
6532
- "argsType": "string",
6796
+ "argsType": "PluginWallType",
6533
6797
  "resultType": "PluginBuildingType | null"
6534
6798
  },
6535
6799
  {
@@ -6571,6 +6835,14 @@
6571
6835
  "argsType": "ComponentHandle[]",
6572
6836
  "resultType": "PluginDesignChangeResult"
6573
6837
  },
6838
+ {
6839
+ "path": "design.update.beam",
6840
+ "namespace": "design.update",
6841
+ "summary": "Replace a native beam family while preserving its authored axis. Values use mm/degrees.",
6842
+ "examplePrompts": [],
6843
+ "argsType": "ComponentHandle",
6844
+ "resultType": "PluginDesignChangeResult"
6845
+ },
6574
6846
  {
6575
6847
  "path": "design.update.buildableEnvelope",
6576
6848
  "namespace": "design.update",
@@ -6596,6 +6868,14 @@
6596
6868
  "argsType": "ComponentHandle",
6597
6869
  "resultType": "PluginDesignChangeResult"
6598
6870
  },
6871
+ {
6872
+ "path": "design.update.column",
6873
+ "namespace": "design.update",
6874
+ "summary": "Replace a native column family while preserving its authored axis. Values use mm/degrees.",
6875
+ "examplePrompts": [],
6876
+ "argsType": "ComponentHandle",
6877
+ "resultType": "PluginDesignChangeResult"
6878
+ },
6599
6879
  {
6600
6880
  "path": "design.update.floor",
6601
6881
  "namespace": "design.update",
@@ -6863,7 +7143,7 @@
6863
7143
  {
6864
7144
  "path": "design.windows.getDimensions",
6865
7145
  "namespace": "design.windows",
6866
- "summary": "Get a window's full dimensions in one call — width along the wall, vertical height, and thickness through the wall — measured in the window's local oriented space.",
7146
+ "summary": "Get evaluated opening width/height and host thickness in Snaptrude units. The opening can differ from the width/height input parameters.",
6867
7147
  "examplePrompts": [
6868
7148
  "What are the dimensions of this window?",
6869
7149
  "How big is the selected window?",
@@ -7369,7 +7649,7 @@
7369
7649
  "Add a red arrow from the title to the plan view",
7370
7650
  "Point an arrow at the top-left view on the cover sheet\n\n# Example\n```ts\nconst { shapeId } = await snaptrude.presentation.annotate.arrow(\n\"sheet_1\",\n{ x: 100, y: 200 },\n{ x: 300, y: 250 },\n{ color: \"red\" },\n)\n```"
7371
7651
  ],
7372
- "argsType": "string",
7652
+ "argsType": "string | undefined",
7373
7653
  "resultType": "PluginPresentationAnnotateResult"
7374
7654
  },
7375
7655
  {
@@ -7381,7 +7661,7 @@
7381
7661
  "Put a yellow note on the cover sheet",
7382
7662
  "Leave a note next to the ground floor plan\n\n# Example\n```ts\nconst { shapeId } = await snaptrude.presentation.annotate.note(\n\"sheet_1\",\n\"Review this wall\",\n{ position: { x: 60, y: 120 }, color: \"yellow\" },\n)\n```"
7383
7663
  ],
7384
- "argsType": "string",
7664
+ "argsType": "string | undefined",
7385
7665
  "resultType": "PluginPresentationAnnotateResult"
7386
7666
  },
7387
7667
  {
@@ -7393,7 +7673,7 @@
7393
7673
  "Add a red rectangle highlight to the sheet",
7394
7674
  "Draw an ellipse around the entrance on the cover sheet\n\n# Example\n```ts\nconst { shapeId } = await snaptrude.presentation.annotate.shape(\n\"sheet_1\",\n\"cloud\",\n{ x: 80, y: 80, w: 240, h: 160 },\n{ color: \"red\" },\n)\n```"
7395
7675
  ],
7396
- "argsType": "string",
7676
+ "argsType": "string | undefined",
7397
7677
  "resultType": "PluginPresentationAnnotateResult"
7398
7678
  },
7399
7679
  {
@@ -7406,7 +7686,7 @@
7406
7686
  "Caption this view with \"Proposed layout\"",
7407
7687
  "Put a red note on the sheet\n\n# Example\n```ts\nconst { shapeId } = await snaptrude.presentation.annotate.text(\n\"sheet_1\",\n\"Ground Floor\",\n{ position: { x: 40, y: 40 }, size: \"xl\", color: \"blue\" },\n)\n```"
7408
7688
  ],
7409
- "argsType": "string",
7689
+ "argsType": "string | undefined",
7410
7690
  "resultType": "PluginPresentationAnnotateTextResult"
7411
7691
  },
7412
7692
  {
@@ -7509,20 +7789,325 @@
7509
7789
  "argsType": "string",
7510
7790
  "resultType": "PluginPresentationDiagramsPlaceResult"
7511
7791
  },
7792
+ {
7793
+ "path": "presentation.drawings.applyPreset",
7794
+ "namespace": "presentation.drawings",
7795
+ "summary": "Bind a native kernel plan to a view preset and clear its declared overrides, so it takes the preset's styles. Local title, proposal and building text is kept. One Present undo step. Presets apply only to drawings whose `getCapabilities(drawingId).presets` is `true`.",
7796
+ "examplePrompts": [
7797
+ "Apply the presentation plan preset to this drawing",
7798
+ "Use the Planning Issue style on every plan drawing",
7799
+ "Make this drawing look like the other plans\n\n# Example\n```ts\nconst presets = await snaptrude.presentation.viewPresets.list()\nconst preset = presets.find((each) => each.name === \"Planning Issue\")\nif (preset) await snaptrude.presentation.drawings.applyPreset(drawing.id, preset.id)\n```"
7800
+ ],
7801
+ "argsType": "string",
7802
+ "resultType": "PluginDrawing"
7803
+ },
7804
+ {
7805
+ "path": "presentation.drawings.copy",
7806
+ "namespace": "presentation.drawings",
7807
+ "summary": "Duplicate a drawing with its labels and annotations (native duplication, offset slightly from the original). One Present undo step. The copy keeps the original's source view, scale, crop, styles and preset binding.",
7808
+ "examplePrompts": [
7809
+ "Duplicate this drawing",
7810
+ "Make a copy of the ground floor plan drawing",
7811
+ "Copy this drawing so I can try a different style\n\n# Example\n```ts\nconst copy = await snaptrude.presentation.drawings.copy(drawing.id)\nawait snaptrude.presentation.drawings.rename(copy.id, \"Ground Floor (option B)\")\n```"
7812
+ ],
7813
+ "argsType": "string",
7814
+ "resultType": "PluginDrawing"
7815
+ },
7816
+ {
7817
+ "path": "presentation.drawings.create",
7818
+ "namespace": "presentation.drawings",
7819
+ "summary": "Generate a drawing from a saved view. Creates the drawing beside its source view on the canvas, never on a sheet; to put a drawing on a sheet use `presentation.sheets.place(sheetId, viewId)` (fits it to the sheet) or `presentation.sheets.placeDrawing(sheetId, drawingId)` (moves this drawing onto the sheet, scaled down to fit). Omit `position` unless the user asked for a specific place: the host puts the new drawing next to its source view, clear of other drawings. An explicit `position` (page coordinates, the drawing's centre) is kept and can land on top of an existing drawing. The user's selection is left as it was. Changes the drawing, not the Present camera. The Present view may follow the drawing as a courtesy to a user watching (never zooming in, not while the camera is locked); to look at it, call `presentation.camera.zoomTo(drawing.id)` then `presentation.camera.capture()`. `scale` must be a standard architectural scale denominator (100 means 1:100) in the project's unit system; any other value is rejected. Metric: 10, 20, 50, 100, 150, 200, 250, 500, 1000. Imperial detail: 12, 16, 24, 32, 48, 64, 96, 128, 192, 384, 768, 1536 (1\" = 1' to 1/128\" = 1'; 48 is 1/4\" = 1', 96 is 1/8\" = 1'). Imperial site: 120, 240, 360, 480, 600, 1200, 2400, 3600, 4800 (1\" = 10' to 1\" = 400'). Pick the LARGEST standard scale (smallest denominator) at which the view still fits its frame or sheet and its room labels stay readable: for a building floor plan that is usually 1:50 to 1:200 (1/4\" = 1' to 1/16\" = 1'). Never use a site-sized scale (1:500 and up, 1/64\" = 1' (768) and smaller, 1\" = 20' (240) and up) for a single building plan unless the user asked for it. `scale` applies to plans, site plans and elevations; leave it out for a 3D view. After creating, read `labels.getLayout(drawingId)`: when labels are unplaced and carry a `suggestedScale`, move to that larger scale with `setScale`. To apply a preset, create first and then call `applyPreset`.",
7820
+ "examplePrompts": [
7821
+ "Create a drawing from the ground floor view",
7822
+ "Make a 1:100 plan drawing of level 2",
7823
+ "Draw the north elevation at 1/8\" = 1'",
7824
+ "Put the site plan view on the Present canvas as a drawing\n\n# Example\n```ts\nconst { views } = await snaptrude.presentation.views.list()\nconst plan = views.find((view) => view.kind === \"plan\")!\nconst drawing = await snaptrude.presentation.drawings.create(plan.id, { scale: 100 })\nawait snaptrude.presentation.camera.zoomTo(drawing.id)\nconst { image } = await snaptrude.presentation.camera.capture()\n// To put it on a sheet: await snaptrude.presentation.sheets.placeDrawing(sheet.id, drawing.id)\n```"
7825
+ ],
7826
+ "argsType": "string",
7827
+ "resultType": "PluginDrawing"
7828
+ },
7829
+ {
7830
+ "path": "presentation.drawings.delete",
7831
+ "namespace": "presentation.drawings",
7832
+ "summary": "Delete a drawing with its labels and annotations, as one Present undo step. The source saved view is not deleted.",
7833
+ "examplePrompts": [
7834
+ "Delete this drawing",
7835
+ "Remove the old elevation drawing from the canvas",
7836
+ "Get rid of the duplicate plan drawing\n\n# Example\n```ts\nawait snaptrude.presentation.drawings.delete(drawing.id)\n```"
7837
+ ],
7838
+ "argsType": "string",
7839
+ "resultType": "void"
7840
+ },
7841
+ {
7842
+ "path": "presentation.drawings.export",
7843
+ "namespace": "presentation.drawings",
7844
+ "summary": "Export one drawing, with its labels and annotations, without a sheet. PDF size follows the drawing's canvas bounds; SVG and PDF keep vector content, raster fallbacks stay raster. `resolution` applies to raster formats. It does not wait for the canvas to paint, so it works while the user is on another browser tab. `download: true` starts a browser download and returns metadata only (never send large base64 to an agent); otherwise `files` carry `dataBase64`. `downloadStarted` means initiated, not proof of an OS-saved file. Layout warnings are returned. `fileName` is a base name WITHOUT an extension (\"Floor Pattern View\", never \"Floor Pattern View.pdf\"): the host appends .pdf/.svg/.png/.jpg for the format, and a name ending in .pdf, .svg, .png, .jpg or .jpeg, a dot or a space is rejected.",
7845
+ "examplePrompts": [
7846
+ "Export this drawing as a PDF",
7847
+ "Download the ground floor plan drawing as an SVG",
7848
+ "Save this drawing as a high-resolution PNG\n\n# Example\n```ts\nawait snaptrude.presentation.drawings.getStatus(drawing.id, { waitMs: 10_000 })\nconst result = await snaptrude.presentation.drawings.export(drawing.id, \"pdf\", {\nfileName: \"Ground Floor Plan\",\ndownload: true,\n})\n```"
7849
+ ],
7850
+ "argsType": "string",
7851
+ "resultType": "PluginDrawingExportResult"
7852
+ },
7853
+ {
7854
+ "path": "presentation.drawings.get",
7855
+ "namespace": "presentation.drawings",
7856
+ "summary": "Read one drawing by its stable id.",
7857
+ "examplePrompts": [
7858
+ "Does the ground floor drawing still exist?",
7859
+ "What preset is this drawing using?",
7860
+ "Read the scale and crop of this drawing\n\n# Example\n```ts\nconst current = await snaptrude.presentation.drawings.get(drawing.id)\nif (current) console.log(current.scale, current.presetId)\n```"
7861
+ ],
7862
+ "argsType": "string",
7863
+ "resultType": "PluginDrawing | null"
7864
+ },
7865
+ {
7866
+ "path": "presentation.drawings.getCapabilities",
7867
+ "namespace": "presentation.drawings",
7868
+ "summary": "Read what a drawing supports: its actual renderer, whether it takes presets (native kernel plans only), label layout and an architectural scale, the standard scales for this project, and its export formats. Read this before preset, scale, label-layout, style or export writes instead of inferring support from the source view.",
7869
+ "examplePrompts": [
7870
+ "What editing capabilities does this drawing support?",
7871
+ "Can I apply a preset to this drawing?",
7872
+ "Which scales can this drawing use?\n\n# Example\n```ts\nconst capabilities = await snaptrude.presentation.drawings.getCapabilities(drawing.id)\nif (capabilities.presets) {\nawait snaptrude.presentation.drawings.applyPreset(drawing.id, preset.id)\n}\n```"
7873
+ ],
7874
+ "argsType": "string",
7875
+ "resultType": "PluginDrawingCapabilities"
7876
+ },
7877
+ {
7878
+ "path": "presentation.drawings.getStatus",
7879
+ "namespace": "presentation.drawings",
7880
+ "summary": "Read a drawing's generation, label-layout and asset-upload state, optionally waiting up to `waitMs` (0 by default, at most 30,000) for it to become export-ready and uploaded. A timeout is not an error: the current state is returned. Read this before export or before closing Present mode.",
7881
+ "examplePrompts": [
7882
+ "Is this drawing ready to export?",
7883
+ "Wait for the new drawing to finish generating",
7884
+ "Has the drawing been uploaded yet?\n\n# Example\n```ts\nconst status = await snaptrude.presentation.drawings.getStatus(drawing.id, {\nwaitMs: 10_000,\n})\nif (!status.exportReady) console.warn(status.warnings)\n```"
7885
+ ],
7886
+ "argsType": "string",
7887
+ "resultType": "PluginDrawingStatus"
7888
+ },
7889
+ {
7890
+ "path": "presentation.drawings.getStyles",
7891
+ "namespace": "presentation.drawings",
7892
+ "summary": "Read a drawing's effective style categories (preset plus its own overrides) and the controls each category accepts. Always read this before {@linkcode PluginPresentationDrawingsApi.updateStyles}: accepted categories and controls depend on the drawing, and an `absent` category rejects writes. Do not echo a whole `settings` record as a patch (legacy reads may include the read-only `disable` flag and `-1` for unset opacity).",
7893
+ "examplePrompts": [
7894
+ "Show the editable styles for this drawing",
7895
+ "What line weight are the walls drawn with?",
7896
+ "Which categories can I restyle on this plan?\n\n# Example\n```ts\nconst styles = await snaptrude.presentation.drawings.getStyles(drawing.id)\nconst editable = styles.categories.filter((row) => !row.absent)\n```"
7897
+ ],
7898
+ "argsType": "string",
7899
+ "resultType": "PluginDrawingStyles"
7900
+ },
7901
+ {
7902
+ "path": "presentation.drawings.labels.getLayout",
7903
+ "namespace": "presentation.drawings.labels",
7904
+ "summary": "Read the label-layout diagnostics of a drawing: labels that could not be placed cleanly (each with a `suggestedScale` at which it would fit), pinned labels, merged duplicates and dropped rows. Reading never hides a label: an unplaced label is still shown at a best-effort position.",
7905
+ "examplePrompts": [
7906
+ "Check this drawing for overlapping labels",
7907
+ "Do all the room names fit on the ground floor drawing?",
7908
+ "Which scale would make the labels on this plan readable?\n\n# Example\n```ts\nconst layout = await snaptrude.presentation.drawings.labels.getLayout(drawing.id)\nconst suggested = layout.unplaced.find((row) => row.suggestedScale)?.suggestedScale\nif (suggested) await snaptrude.presentation.drawings.setScale(drawing.id, suggested)\n```"
7909
+ ],
7910
+ "argsType": "string",
7911
+ "resultType": "PluginDrawingLabelLayout"
7912
+ },
7913
+ {
7914
+ "path": "presentation.drawings.labels.list",
7915
+ "namespace": "presentation.drawings.labels",
7916
+ "summary": "List every text label on a drawing, including labels the user or the layout has hidden. An agent's own annotations under the drawing are not labels and are not listed.",
7917
+ "examplePrompts": [
7918
+ "List all labels in this drawing",
7919
+ "Which room labels are hidden on the ground floor drawing?",
7920
+ "Show me the text of every label on this plan\n\n# Example\n```ts\nconst labels = await snaptrude.presentation.drawings.labels.list(drawing.id)\nconst hidden = labels.filter((label) => label.hidden)\n```"
7921
+ ],
7922
+ "argsType": "string",
7923
+ "resultType": "PluginPlacedViewLabel[]"
7924
+ },
7925
+ {
7926
+ "path": "presentation.drawings.labels.move",
7927
+ "namespace": "presentation.drawings.labels",
7928
+ "summary": "Move a label within its drawing. A room label keeps the new position as a native pin at the drawing's current architectural scale; other labels move as plain text shapes. One Present undo step.",
7929
+ "examplePrompts": [
7930
+ "Move the Kitchen label up a little",
7931
+ "Put the living room name in the middle of the room",
7932
+ "Nudge this label to the left\n\n# Example\n```ts\nconst [label] = await snaptrude.presentation.drawings.labels.list(drawing.id)\nawait snaptrude.presentation.drawings.labels.move(label.labelId, {\nx: label.position.x,\ny: label.position.y - 20,\n})\n```"
7933
+ ],
7934
+ "argsType": "string",
7935
+ "resultType": "PluginPlacedViewLabel"
7936
+ },
7937
+ {
7938
+ "path": "presentation.drawings.labels.place",
7939
+ "namespace": "presentation.drawings.labels",
7940
+ "summary": "Pin a room label that could not be placed cleanly at the best position the native layout solver finds, at the current architectural scale. May wait up to ten seconds for a reloaded drawing's fit data. One Present undo step.",
7941
+ "examplePrompts": [
7942
+ "Place the labels that do not fit",
7943
+ "Pin the Kitchen label where it fits best",
7944
+ "Fix the overlapping room names on this drawing\n\n# Example\n```ts\nconst { unplaced } = await snaptrude.presentation.drawings.labels.getLayout(drawing.id)\nfor (const row of unplaced) {\nawait snaptrude.presentation.drawings.labels.place(row.labelId)\n}\n```"
7945
+ ],
7946
+ "argsType": "string",
7947
+ "resultType": "boolean"
7948
+ },
7949
+ {
7950
+ "path": "presentation.drawings.labels.reset",
7951
+ "namespace": "presentation.drawings.labels",
7952
+ "summary": "Clear room-label pins (from `move`, `place` or the user) so the native layout places those labels again: at the current architectural scale by default, or at every scale with `{ scope: \"all\" }`. One Present undo step.",
7953
+ "examplePrompts": [
7954
+ "Reset the label positions on this drawing",
7955
+ "Undo all my label moves at every scale",
7956
+ "Let the room labels lay themselves out again\n\n# Example\n```ts\nconst cleared = await snaptrude.presentation.drawings.labels.reset(drawing.id, {\nscope: \"all\",\n})\n```"
7957
+ ],
7958
+ "argsType": "string",
7959
+ "resultType": "number"
7960
+ },
7961
+ {
7962
+ "path": "presentation.drawings.labels.setHidden",
7963
+ "namespace": "presentation.drawings.labels",
7964
+ "summary": "Hide or show a label. This is the user's own visibility, independent of labels the layout or a crop hides. One Present undo step.",
7965
+ "examplePrompts": [
7966
+ "Hide the Store label on this drawing",
7967
+ "Show the corridor label again",
7968
+ "Turn off the label for the plant room\n\n# Example\n```ts\nconst labels = await snaptrude.presentation.drawings.labels.list(drawing.id)\nconst store = labels.find((label) => label.text.startsWith(\"Store\"))\nif (store) await snaptrude.presentation.drawings.labels.setHidden(store.labelId, true)\n```"
7969
+ ],
7970
+ "argsType": "string",
7971
+ "resultType": "PluginPlacedViewLabel"
7972
+ },
7973
+ {
7974
+ "path": "presentation.drawings.list",
7975
+ "namespace": "presentation.drawings",
7976
+ "summary": "List the drawings on the current Present page, loose or on sheets.",
7977
+ "examplePrompts": [
7978
+ "List all drawings in this presentation",
7979
+ "Which drawings are not on a sheet yet?",
7980
+ "What scale is each plan drawing at?\n\n# Example\n```ts\nconst drawings = await snaptrude.presentation.drawings.list()\nconst loose = drawings.filter((drawing) => !drawing.sheetId)\n```"
7981
+ ],
7982
+ "argsType": null,
7983
+ "resultType": "PluginDrawing[]"
7984
+ },
7985
+ {
7986
+ "path": "presentation.drawings.listFonts",
7987
+ "namespace": "presentation.drawings",
7988
+ "summary": "List the font families drawing text can use, from the native catalog (`\"DEFAULT\"` first). Use these names in a style patch's `fontFamily` instead of inventing one.",
7989
+ "examplePrompts": [
7990
+ "Which fonts can I use for drawing labels?",
7991
+ "Is Inter available as a drawing font?",
7992
+ "List the fonts for the title block\n\n# Example\n```ts\nconst fonts = await snaptrude.presentation.drawings.listFonts()\nconst family = fonts.includes(\"Inter\") ? \"Inter\" : \"DEFAULT\"\n```"
7993
+ ],
7994
+ "argsType": null,
7995
+ "resultType": "string[]"
7996
+ },
7997
+ {
7998
+ "path": "presentation.drawings.listPatterns",
7999
+ "namespace": "presentation.drawings",
8000
+ "summary": "List the hatch patterns the native pattern catalog offers. Use these ids in a style patch's `pattern.id` instead of inventing one.",
8001
+ "examplePrompts": [
8002
+ "What hatch patterns can I use?",
8003
+ "List the brick and concrete patterns",
8004
+ "Which fill patterns are available for rooms?\n\n# Example\n```ts\nconst patterns = await snaptrude.presentation.drawings.listPatterns()\nconst brick = patterns.find((pattern) => pattern.label.toLowerCase().includes(\"brick\"))\n```"
8005
+ ],
8006
+ "argsType": null,
8007
+ "resultType": "{ id: string; label: string; group: string }[]"
8008
+ },
8009
+ {
8010
+ "path": "presentation.drawings.rename",
8011
+ "namespace": "presentation.drawings",
8012
+ "summary": "Set the drawing's own title text. The source saved view keeps its name. One Present undo step.",
8013
+ "examplePrompts": [
8014
+ "Rename this drawing to Ground Floor Plan",
8015
+ "Change the title of the elevation drawing",
8016
+ "Call this drawing Level 2 General Arrangement\n\n# Example\n```ts\nawait snaptrude.presentation.drawings.rename(drawing.id, \"Ground Floor Plan\")\n```"
8017
+ ],
8018
+ "argsType": "string",
8019
+ "resultType": "PluginDrawing"
8020
+ },
8021
+ {
8022
+ "path": "presentation.drawings.resetOverrides",
8023
+ "namespace": "presentation.drawings",
8024
+ "summary": "Drop a kernel plan's own style overrides so it matches its bound preset again. Local title, proposal and building text is kept. One Present undo step.",
8025
+ "examplePrompts": [
8026
+ "Reset this drawing to its preset styles",
8027
+ "Undo my style changes on the ground floor plan",
8028
+ "Clear the overrides on this drawing\n\n# Example\n```ts\nawait snaptrude.presentation.drawings.resetOverrides(drawing.id)\n```"
8029
+ ],
8030
+ "argsType": "string",
8031
+ "resultType": "PluginDrawing"
8032
+ },
8033
+ {
8034
+ "path": "presentation.drawings.setCrop",
8035
+ "namespace": "presentation.drawings",
8036
+ "summary": "Crop a drawing to a window of itself, or pass `null` to remove the crop. Crop corners are 0–1 fractions of the uncropped drawing and must satisfy `topLeft < bottomRight` on both axes. One Present undo step. A loose drawing that grows over a neighbour it did not cover before (for example when the crop is removed) moves to the nearest free spot, which `placedViews.setCrop` does not do; an overlap the user made stays, and a drawing on a sheet never moves. Changes the drawing, not the Present camera. The Present view may follow the drawing as a courtesy to a user watching (never zooming in, not while the camera is locked); to look at it, call `presentation.camera.zoomTo(drawing.id)` then `presentation.camera.capture()`.",
8037
+ "examplePrompts": [
8038
+ "Crop this drawing to the left half",
8039
+ "Remove the crop from the site plan drawing",
8040
+ "Show only the top-right corner of this plan\n\n# Example\n```ts\nawait snaptrude.presentation.drawings.setCrop(drawing.id, {\ntopLeft: { x: 0, y: 0 },\nbottomRight: { x: 0.5, y: 1 },\n})\nawait snaptrude.presentation.drawings.setCrop(drawing.id, null)\n```"
8041
+ ],
8042
+ "argsType": "string",
8043
+ "resultType": "PluginDrawing"
8044
+ },
8045
+ {
8046
+ "path": "presentation.drawings.setScale",
8047
+ "namespace": "presentation.drawings",
8048
+ "summary": "Set a drawing's architectural scale; perspective/isometric drawings reject this. `scale` must be a standard architectural scale denominator (100 means 1:100) in the project's unit system; any other value is rejected. Metric: 10, 20, 50, 100, 150, 200, 250, 500, 1000. Imperial detail: 12, 16, 24, 32, 48, 64, 96, 128, 192, 384, 768, 1536 (1\" = 1' to 1/128\" = 1'; 48 is 1/4\" = 1', 96 is 1/8\" = 1'). Imperial site: 120, 240, 360, 480, 600, 1200, 2400, 3600, 4800 (1\" = 10' to 1\" = 400'). Pick the LARGEST standard scale (smallest denominator) at which the view still fits its frame or sheet and its room labels stay readable: for a building floor plan that is usually 1:50 to 1:200 (1/4\" = 1' to 1/16\" = 1'). Never use a site-sized scale (1:500 and up, 1/64\" = 1' (768) and smaller, 1\" = 20' (240) and up) for a single building plan unless the user asked for it. A loose drawing that grows over a neighbour it did not cover before moves to the nearest free spot, which `placedViews.setScale` does not do; an overlap the user made stays, and a drawing on a sheet never moves. Changes the drawing, not the Present camera. The Present view may follow the drawing as a courtesy to a user watching (never zooming in, not while the camera is locked); to look at it, call `presentation.camera.zoomTo(drawing.id)` then `presentation.camera.capture()`.",
8049
+ "examplePrompts": [
8050
+ "Set this drawing to 1:50",
8051
+ "Change the plan drawing scale to 1/4\" = 1'",
8052
+ "Make the ground floor drawing bigger so the labels fit\n\n# Example\n```ts\nconst layout = await snaptrude.presentation.drawings.labels.getLayout(drawing.id)\nconst suggested = layout.unplaced.find((row) => row.suggestedScale)?.suggestedScale\nawait snaptrude.presentation.drawings.setScale(drawing.id, suggested ?? 50)\n```"
8053
+ ],
8054
+ "argsType": "string",
8055
+ "resultType": "PluginDrawing"
8056
+ },
8057
+ {
8058
+ "path": "presentation.drawings.updateContent",
8059
+ "namespace": "presentation.drawings",
8060
+ "summary": "Regenerate one to 100 drawings from their source views, after the model or the view changed. Waits for the update to finish.",
8061
+ "examplePrompts": [
8062
+ "Update this drawing with my latest model changes",
8063
+ "Refresh all the drawings",
8064
+ "Regenerate the ground floor plan drawing\n\n# Example\n```ts\nconst drawings = await snaptrude.presentation.drawings.list()\nconst results = await snaptrude.presentation.drawings.updateContent(\ndrawings.map((drawing) => drawing.id),\n)\n```"
8065
+ ],
8066
+ "argsType": "string[]",
8067
+ "resultType": "{ drawingId: string; updated: boolean }[]"
8068
+ },
8069
+ {
8070
+ "path": "presentation.drawings.updateStyles",
8071
+ "namespace": "presentation.drawings",
8072
+ "summary": "Merge a sparse style patch into one category of a drawing, as one Present undo step. Nested objects merge rather than replace the row. Line and outline weights are paper millimetres (0–2.11); opacity is 0–100; colours are `#rrggbb`. On a kernel plan the patch becomes the drawing's own overrides of its preset; other drawings take the legacy placed-view category patch. An absent category, an unsupported field or an invalid value rejects the whole write.",
8073
+ "examplePrompts": [
8074
+ "Make the walls on this drawing thicker",
8075
+ "Fill the rooms at 60% opacity with a larger hatch",
8076
+ "Turn off the door tags on this plan\n\n# Example\n```ts\nconst styles = await snaptrude.presentation.drawings.getStyles(drawing.id)\nconst space = styles.categories.find((row) => row.category === \"Space\")\nif (space && !space.absent && space.controls.some((control) => control.key === \"opacity\")) {\nawait snaptrude.presentation.drawings.updateStyles(drawing.id, \"Space\", {\nopacity: 60,\npattern: { scale: 1.5 },\n})\n}\n```"
8077
+ ],
8078
+ "argsType": "string",
8079
+ "resultType": "PluginDrawingStyles"
8080
+ },
7512
8081
  {
7513
8082
  "path": "presentation.export",
7514
8083
  "namespace": "presentation",
7515
- "summary": "Export the presentation's layout sheets to a downloadable file (PDF / PNG / JPG) and return the encoded bytes as base64. Wraps the Present-mode Export dialog pipeline headlessly. Requires Present mode to be open.",
8084
+ "summary": "Export the presentation's layout sheets to a downloadable file (PDF / PNG / JPG). Return base64 by default; `download: true` initiates browser downloads and returns metadata without base64. Requires Present mode to be open. `fileName` is a base name WITHOUT an extension (\"Floor Pattern View\", never \"Floor Pattern View.pdf\"): the host appends the extension for the format, and a name ending in .pdf, .svg, .png, .jpg or .jpeg, a dot or a space is rejected.",
7516
8085
  "examplePrompts": [
7517
8086
  "Export the presentation as a PDF",
7518
8087
  "Download all sheets as a single PDF",
7519
8088
  "Export sheet 1 as a PNG",
7520
8089
  "Save the presentation sheets as JPG images",
7521
- "Export these sheets to PDF at high resolution\n\n# Example\n```ts\nconst { files } = await snaptrude.presentation.export(\"pdf\")\n```"
8090
+ "Export these sheets to PDF at high resolution\n\n# Example\n```ts\nconst { files } = await snaptrude.presentation.export(\"pdf\")\nconst download = await snaptrude.presentation.export(\"pdf\", { download: true })\n```"
7522
8091
  ],
7523
8092
  "argsType": "PluginPresentationExportFormat",
7524
8093
  "resultType": "PluginPresentationExportResult"
7525
8094
  },
8095
+ {
8096
+ "path": "presentation.export",
8097
+ "namespace": "presentation",
8098
+ "summary": "",
8099
+ "examplePrompts": [],
8100
+ "argsType": "PluginPresentationExportFormat",
8101
+ "resultType": "PluginPresentationExportDownloadResult"
8102
+ },
8103
+ {
8104
+ "path": "presentation.export",
8105
+ "namespace": "presentation",
8106
+ "summary": "",
8107
+ "examplePrompts": [],
8108
+ "argsType": "PluginPresentationExportFormat",
8109
+ "resultType": "PluginPresentationExportResult | PluginPresentationExportDownloadResult"
8110
+ },
7526
8111
  {
7527
8112
  "path": "presentation.import.image",
7528
8113
  "namespace": "presentation.import",
@@ -7788,7 +8373,7 @@
7788
8373
  {
7789
8374
  "path": "presentation.placedViews.setScale",
7790
8375
  "namespace": "presentation.placedViews",
7791
- "summary": "Set a placed view's architectural scale.",
8376
+ "summary": "Set a placed view's architectural scale. `scale` must be a standard architectural scale denominator (100 means 1:100) in the project's unit system; any other value is rejected. Metric: 10, 20, 50, 100, 150, 200, 250, 500, 1000. Imperial detail: 12, 16, 24, 32, 48, 64, 96, 128, 192, 384, 768, 1536 (1\" = 1' to 1/128\" = 1'; 48 is 1/4\" = 1', 96 is 1/8\" = 1'). Imperial site: 120, 240, 360, 480, 600, 1200, 2400, 3600, 4800 (1\" = 10' to 1\" = 400'). Pick the LARGEST standard scale (smallest denominator) at which the view still fits its frame or sheet and its room labels stay readable: for a building floor plan that is usually 1:50 to 1:200 (1/4\" = 1' to 1/16\" = 1'). Never use a site-sized scale (1:500 and up, 1/64\" = 1' (768) and smaller, 1\" = 20' (240) and up) for a single building plan unless the user asked for it.",
7792
8377
  "examplePrompts": [
7793
8378
  "Set the plan to 1:100",
7794
8379
  "Change the placed floor plan to 1:50 scale",
@@ -7823,6 +8408,99 @@
7823
8408
  "argsType": "string",
7824
8409
  "resultType": "PluginPlacedViewCategoryStyles"
7825
8410
  },
8411
+ {
8412
+ "path": "presentation.sections.create",
8413
+ "namespace": "presentation.sections",
8414
+ "summary": "Draw a section line from `start` to `end` on the plan. The section looks along the line's direction turned a quarter turn — a line drawn toward +x looks toward +z; flip it with `update(id, { isFlipped: true })`. Its slice defaults to the building's full height and its depth to the far side of the model. Write-gated; one undo step.",
8415
+ "examplePrompts": [
8416
+ "Cut a section through the middle of the building, east to west",
8417
+ "Add a section across the stair core",
8418
+ "Draw a longitudinal section and open it\n\n# Example\n```ts\nconst section = await snaptrude.presentation.sections.create(\n{ x: -40, z: 10 },\n{ x: 40, z: 10 },\n{ name: \"Longitudinal\", isActive: true },\n)\n```"
8419
+ ],
8420
+ "argsType": "PluginSectionPoint",
8421
+ "resultType": "PluginSection"
8422
+ },
8423
+ {
8424
+ "path": "presentation.sections.delete",
8425
+ "namespace": "presentation.sections",
8426
+ "summary": "Delete a section. Closes its view first if it is open. Write-gated; one undo step.",
8427
+ "examplePrompts": [
8428
+ "Delete Section B\n\n# Example\n```ts\nawait snaptrude.presentation.sections.delete(sectionId)\n```"
8429
+ ],
8430
+ "argsType": "string",
8431
+ "resultType": "boolean"
8432
+ },
8433
+ {
8434
+ "path": "presentation.sections.get",
8435
+ "namespace": "presentation.sections",
8436
+ "summary": "Get one section by id.",
8437
+ "examplePrompts": [
8438
+ "Where does Section A run?",
8439
+ "How deep is this section?\n\n# Example\n```ts\nconst section = await snaptrude.presentation.sections.get(sectionId)\nconsole.log(section?.start, section?.end)\n```"
8440
+ ],
8441
+ "argsType": "string",
8442
+ "resultType": "PluginSection | null"
8443
+ },
8444
+ {
8445
+ "path": "presentation.sections.getActive",
8446
+ "namespace": "presentation.sections",
8447
+ "summary": "Get the section whose view is open.",
8448
+ "examplePrompts": [
8449
+ "Which section am I looking at?\n\n# Example\n```ts\nconst open = await snaptrude.presentation.sections.getActive()\n```"
8450
+ ],
8451
+ "argsType": null,
8452
+ "resultType": "PluginSection | null"
8453
+ },
8454
+ {
8455
+ "path": "presentation.sections.getCut",
8456
+ "namespace": "presentation.sections",
8457
+ "summary": "What a section cuts: every element its cutting plane passes through within the section's extents, with the cut's area, outline length and extent on the plane, largest first. Computed from the model, not from the drawing, so it needs no open view and works however the section is shown; furniture is left out, as in the drawing, and so is anything hidden in the model. Areas are exact for closed solids. Repeated calls reuse the cuts of elements that have not changed. Read-only.",
8458
+ "examplePrompts": [
8459
+ "Which walls does Section A cut?",
8460
+ "How thick is the slab where the section crosses it?",
8461
+ "Does this section go through the stair?",
8462
+ "What is the floor-to-floor height in this section?\n\n# Example\n```ts\nconst cut = await snaptrude.presentation.sections.getCut(sectionId)\nconst walls = cut.elements.filter((element) => element.type === \"wall\")\nconst thickest = walls[0]\nconsole.log(thickest.extent.uMax - thickest.extent.uMin)\n```"
8463
+ ],
8464
+ "argsType": "string",
8465
+ "resultType": "PluginSectionCut"
8466
+ },
8467
+ {
8468
+ "path": "presentation.sections.list",
8469
+ "namespace": "presentation.sections",
8470
+ "summary": "List the project's sections, in Views panel order.",
8471
+ "examplePrompts": [
8472
+ "Which sections are there?",
8473
+ "List the section lines in this project",
8474
+ "Is there a section through the stair?\n\n# Example\n```ts\nconst sections = await snaptrude.presentation.sections.list()\n```"
8475
+ ],
8476
+ "argsType": null,
8477
+ "resultType": "PluginSection[]"
8478
+ },
8479
+ {
8480
+ "path": "presentation.sections.setActive",
8481
+ "namespace": "presentation.sections",
8482
+ "summary": "Open a section's view, or close the open one with `null`. Opening frames the section's saved camera, or a straight-on view when it has none. Closing returns to 3D; with no section view open, `null` does nothing. Not an edit: nothing is added to the undo history.",
8483
+ "examplePrompts": [
8484
+ "Open Section A",
8485
+ "Show me the section through the atrium",
8486
+ "Close the section view\n\n# Example\n```ts\nawait snaptrude.presentation.sections.setActive(section.sectionId)\nawait snaptrude.presentation.sections.setActive(null)\n```"
8487
+ ],
8488
+ "argsType": "string | null",
8489
+ "resultType": "PluginSection | null"
8490
+ },
8491
+ {
8492
+ "path": "presentation.sections.update",
8493
+ "namespace": "presentation.sections",
8494
+ "summary": "Change a section. Only the given fields change; the whole patch is one undo step. Flipping without a `depth` carries the depth to the far side of the model in the new direction, as `create` does. Write-gated.",
8495
+ "examplePrompts": [
8496
+ "Make Section A look the other way",
8497
+ "Only show the ground floor in this section",
8498
+ "Rename the section to \"Through atrium\"",
8499
+ "Move the section line 5 m north\n\n# Example\n```ts\nawait snaptrude.presentation.sections.update(sectionId, {\nisFlipped: true,\ndepth: 60,\n})\n```"
8500
+ ],
8501
+ "argsType": "string",
8502
+ "resultType": "PluginSection"
8503
+ },
7826
8504
  {
7827
8505
  "path": "presentation.shapes.list",
7828
8506
  "namespace": "presentation.shapes",
@@ -7925,17 +8603,31 @@
7925
8603
  {
7926
8604
  "path": "presentation.sheets.place",
7927
8605
  "namespace": "presentation.sheets",
7928
- "summary": "Place a saved view onto a sheet.",
8606
+ "summary": "Place a saved view onto a sheet. This is the call that puts a view on a sheet (`presentation.drawings.create` makes a drawing beside its source view, not on a sheet). When `scale` is omitted the view is fitted to the target sheet: a 2D or site-plan view is placed at the largest standard scale at which it fits inside the target sheet's margin, and never at a larger scale than the normal view drop would pick; a 3D view has no scale, so it is shrunk evenly to fit instead. This is the same fit as `placeDrawing`. Omit `position` unless the user asked for a specific place. Without a `position` the drawing goes to the sheet centre when that is free, otherwise to the nearest free spot to the centre inside the margin, beside the drawings already there; when there is no free spot it is centred anyway and the result has `overlaps: true`. With a `position` it is placed as given, and the result has `overlaps: true` when it covers another drawing, but it is not moved. In both cases only other drawings count (placed views and their title blocks and labels): text, images and other shapes on the sheet are ignored. Each call fits one view to the whole sheet, so a second fitted view often has no free spot: when several views should share a sheet, pass a `scale` small enough for all of them; otherwise use `sheets.create` per view. When the result's `overlaps` is true, move the drawing or put it on its own sheet. An explicit `scale` is always kept, even when the drawing (title block included) does not fit inside the sheet's margin at that scale; the result then has `overflows: true`. When it is true, pass a smaller scale (larger denominator), omit `scale` to fit, or use a larger sheet. `scale` must be a standard architectural scale denominator (100 means 1:100) in the project's unit system; any other value is rejected. Metric: 10, 20, 50, 100, 150, 200, 250, 500, 1000. Imperial detail: 12, 16, 24, 32, 48, 64, 96, 128, 192, 384, 768, 1536 (1\" = 1' to 1/128\" = 1'; 48 is 1/4\" = 1', 96 is 1/8\" = 1'). Imperial site: 120, 240, 360, 480, 600, 1200, 2400, 3600, 4800 (1\" = 10' to 1\" = 400'). Pick the LARGEST standard scale (smallest denominator) at which the view still fits its frame or sheet and its room labels stay readable: for a building floor plan that is usually 1:50 to 1:200 (1/4\" = 1' to 1/16\" = 1'). Never use a site-sized scale (1:500 and up, 1/64\" = 1' (768) and smaller, 1\" = 20' (240) and up) for a single building plan unless the user asked for it.",
7929
8607
  "examplePrompts": [
7930
8608
  "Place the floor plan on Sheet 1",
7931
8609
  "Add this 3D view to the cover sheet",
7932
8610
  "Drop the site plan onto the layout sheet at 100, 200",
7933
8611
  "Put the Ground Floor view on sheet_1 at 1:100 scale",
7934
- "Place the plan on the cover sheet at quarter-inch scale\n\n# Example\n```ts\nconst { shapeId } = await snaptrude.presentation.sheets.place(\"sheet_1\", \"view_123\", {\nscale: 100, // 1:100 (metric project)\n})\n```"
8612
+ "Place the plan on the cover sheet at quarter-inch scale",
8613
+ "Add a floor plan drawing of each storey to this sheet\n\n# Example\n```ts\nconst { shapeId } = await snaptrude.presentation.sheets.place(\"sheet_1\", \"view_123\", {\nscale: 100, // 1:100 (metric project)\n})\n```"
7935
8614
  ],
7936
8615
  "argsType": "string",
7937
8616
  "resultType": "PluginPresentationSheetsPlaceResult"
7938
8617
  },
8618
+ {
8619
+ "path": "presentation.sheets.placeDrawing",
8620
+ "namespace": "presentation.sheets",
8621
+ "summary": "Move an existing drawing onto a sheet without copying or regenerating it, scaled down to fit the sheet when it is too big. `presentation.drawings.create` leaves a drawing beside its source view, not on a sheet; this is the call that puts it on one. To place a saved view on a sheet in one call, use `sheets.place(sheetId, viewId)`, which fits it the same way. By default (`fit` true or omitted) a drawing larger than the sheet's drawable area (the sheet inside its margin) is moved to the LARGEST standard architectural scale at which it fits; a drawing that already fits keeps its scale, and a drawing is never scaled up. A 3D drawing has no architectural scale, so it is shrunk uniformly to fit instead. With `fit: false` the scale is kept and a drawing that does not fit is rejected with an error naming the drawing, the sheet and the scale, and saying to call `placeDrawing` without `fit: false` to fit it, or use a larger sheet. When even the smallest standard scale does not fit, the call is rejected with an error suggesting a larger sheet size. Without a `position` the drawing goes to the sheet centre when that is free, otherwise to the nearest free spot to the centre inside the margin, beside the drawings already there; when there is no free spot it is centred anyway and the result has `overlaps: true`. With a `position` it is placed as given, and the result has `overlaps: true` when it covers another drawing, but it is not moved. In both cases only other drawings count (placed views and their title blocks and labels): text, images and other shapes on the sheet are ignored. Each call fits one drawing to the whole sheet, so a second fitted drawing often has no free spot: when several drawings should share a sheet, give them scales small enough for all of them; otherwise use `sheets.create` per drawing. The position is sheet-local. The drawing's stable id remains unchanged; `shapeId` therefore identifies the moved drawing. The result reports the architectural scale the drawing has on the sheet and whether this call changed it; a host that reports it also says whether the drawing `overlaps` another drawing on the sheet (move it or put it on its own sheet when true).",
8622
+ "examplePrompts": [
8623
+ "Move this drawing onto the cover sheet",
8624
+ "Place drawing_1 at the center of sheet_2",
8625
+ "Put the level 2 plan drawing on the Level 2 Plan sheet",
8626
+ "Add the floor plan drawings to this sheet\n\n# Example\n```ts\nconst { scale, rescaled } = await snaptrude.presentation.sheets.placeDrawing(\nsheet.id,\ndrawing.id,\n)\n```"
8627
+ ],
8628
+ "argsType": "string",
8629
+ "resultType": "PluginPresentationSheetsPlaceDrawingResult"
8630
+ },
7939
8631
  {
7940
8632
  "path": "presentation.sheets.rename",
7941
8633
  "namespace": "presentation.sheets",
@@ -8059,6 +8751,90 @@
8059
8751
  "argsType": "string",
8060
8752
  "resultType": "PluginCanvasShape"
8061
8753
  },
8754
+ {
8755
+ "path": "presentation.viewPresets.copy",
8756
+ "namespace": "presentation.viewPresets",
8757
+ "summary": "Duplicate a preset under a native-generated unique name. Drawing bindings do not change. Not undoable (catalog write). Built-ins can be copied.",
8758
+ "examplePrompts": [
8759
+ "Duplicate this preset",
8760
+ "Make an editable copy of the built-in preset",
8761
+ "Copy the Planning Issue preset so I can change it\n\n# Example\n```ts\nconst copy = await snaptrude.presentation.viewPresets.copy(preset.id)\nawait snaptrude.presentation.viewPresets.rename(copy.id, \"Planning Issue B\")\n```"
8762
+ ],
8763
+ "argsType": "string",
8764
+ "resultType": "PluginViewPreset"
8765
+ },
8766
+ {
8767
+ "path": "presentation.viewPresets.create",
8768
+ "namespace": "presentation.viewPresets",
8769
+ "summary": "Save a kernel-plan drawing's effective styles as a new custom preset and bind that drawing to it. Not undoable (catalog write).",
8770
+ "examplePrompts": [
8771
+ "Save this drawing's styles as a new preset",
8772
+ "Make a preset called Planning Issue from this plan",
8773
+ "Turn my restyled drawing into a reusable style\n\n# Example\n```ts\nconst capabilities = await snaptrude.presentation.drawings.getCapabilities(drawing.id)\nif (capabilities.presets) {\nconst preset = await snaptrude.presentation.viewPresets.create(\"Planning Issue\", {\nfromDrawingId: drawing.id,\n})\n}\n```"
8774
+ ],
8775
+ "argsType": "string",
8776
+ "resultType": "PluginViewPreset"
8777
+ },
8778
+ {
8779
+ "path": "presentation.viewPresets.delete",
8780
+ "namespace": "presentation.viewPresets",
8781
+ "summary": "Delete a custom preset and rebind its drawings to another existing preset. Built-ins cannot be deleted. Not undoable (catalog write).",
8782
+ "examplePrompts": [
8783
+ "Delete this preset",
8784
+ "Remove the old style preset and switch its drawings to the default",
8785
+ "Get rid of the Planning Issue B preset\n\n# Example\n```ts\nconst presets = await snaptrude.presentation.viewPresets.list()\nconst replacement = presets.find((each) => each.builtIn)!\nawait snaptrude.presentation.viewPresets.delete(customPreset.id, {\nreplacementId: replacement.id,\n})\n```"
8786
+ ],
8787
+ "argsType": "string",
8788
+ "resultType": "void"
8789
+ },
8790
+ {
8791
+ "path": "presentation.viewPresets.get",
8792
+ "namespace": "presentation.viewPresets",
8793
+ "summary": "Read one preset by id.",
8794
+ "examplePrompts": [
8795
+ "Which preset is this drawing using?",
8796
+ "Is this preset a built-in one?",
8797
+ "Read the preset bound to the ground floor plan\n\n# Example\n```ts\nconst drawing = await snaptrude.presentation.drawings.get(drawingId)\nconst preset = drawing?.presetId\n? await snaptrude.presentation.viewPresets.get(drawing.presetId)\n: null\n```"
8798
+ ],
8799
+ "argsType": "string",
8800
+ "resultType": "PluginViewPreset | null"
8801
+ },
8802
+ {
8803
+ "path": "presentation.viewPresets.list",
8804
+ "namespace": "presentation.viewPresets",
8805
+ "summary": "List the preset catalog: built-ins first, then custom presets by name.",
8806
+ "examplePrompts": [
8807
+ "List the available drawing style presets",
8808
+ "Which custom presets does this presentation have?",
8809
+ "Is there a Planning Issue preset?\n\n# Example\n```ts\nconst presets = await snaptrude.presentation.viewPresets.list()\nconst custom = presets.filter((preset) => !preset.builtIn)\n```"
8810
+ ],
8811
+ "argsType": null,
8812
+ "resultType": "PluginViewPreset[]"
8813
+ },
8814
+ {
8815
+ "path": "presentation.viewPresets.rename",
8816
+ "namespace": "presentation.viewPresets",
8817
+ "summary": "Rename a custom preset. Names must stay unique; built-ins cannot be renamed. Not undoable (catalog write).",
8818
+ "examplePrompts": [
8819
+ "Rename this preset to Client Review",
8820
+ "Call the copied preset Planning Issue B",
8821
+ "Change the name of my custom drawing style\n\n# Example\n```ts\nawait snaptrude.presentation.viewPresets.rename(preset.id, \"Client Review\")\n```"
8822
+ ],
8823
+ "argsType": "string",
8824
+ "resultType": "PluginViewPreset"
8825
+ },
8826
+ {
8827
+ "path": "presentation.viewPresets.update",
8828
+ "namespace": "presentation.viewPresets",
8829
+ "summary": "Replace a custom preset's values with the effective styles of a drawing already bound to it, then refresh every bound drawing. Built-ins cannot be updated. Not undoable (catalog write).",
8830
+ "examplePrompts": [
8831
+ "Update this preset from the current drawing styles",
8832
+ "Push my style changes to every drawing using this preset",
8833
+ "Save these overrides into the Planning Issue preset\n\n# Example\n```ts\nawait snaptrude.presentation.viewPresets.update(drawing.presetId!, {\nfromDrawingId: drawing.id,\n})\n```"
8834
+ ],
8835
+ "argsType": "string",
8836
+ "resultType": "PluginViewPreset"
8837
+ },
8062
8838
  {
8063
8839
  "path": "presentation.views.capture",
8064
8840
  "namespace": "presentation.views",
@@ -8141,7 +8917,7 @@
8141
8917
  "summary": "List the saved views in the active project.",
8142
8918
  "examplePrompts": [
8143
8919
  "List all the saved views",
8144
- "What 2D and 3D views are in this project?",
8920
+ "What plan, 3D, and elevation views are in this project?",
8145
8921
  "Which view is currently active?",
8146
8922
  "Get the names of every presentation view",
8147
8923
  "Show me the 3D views I can put on a sheet\n\n# Example\n```ts\nconst { views } = await snaptrude.presentation.views.list()\nconst active = views.find((v) => v.isActive)\nconst plans = views.filter((v) => v.type === \"2d\")\n```"