@snaptrude/plugin-core 1.0.2 → 1.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +17 -0
- package/CHANGELOG.md +12 -0
- package/api-manifest.json +130 -2098
- package/dist/api/core/camera/index.d.ts +16 -6
- package/dist/api/core/camera/index.d.ts.map +1 -1
- package/dist/api/core/comment/index.d.ts +7 -3
- package/dist/api/core/comment/index.d.ts.map +1 -1
- package/dist/api/core/geom/create/index.d.ts +69 -21
- package/dist/api/core/geom/create/index.d.ts.map +1 -1
- package/dist/api/core/geom/query/circle.d.ts +31 -11
- package/dist/api/core/geom/query/circle.d.ts.map +1 -1
- package/dist/api/core/geom/query/contour.d.ts +19 -7
- package/dist/api/core/geom/query/contour.d.ts.map +1 -1
- package/dist/api/core/geom/query/curve.d.ts +72 -24
- package/dist/api/core/geom/query/curve.d.ts.map +1 -1
- package/dist/api/core/geom/query/profile.d.ts +19 -7
- package/dist/api/core/geom/query/profile.d.ts.map +1 -1
- package/dist/api/core/geom/update/contour.d.ts +36 -12
- package/dist/api/core/geom/update/contour.d.ts.map +1 -1
- package/dist/api/core/geom/update/curve.d.ts +13 -5
- package/dist/api/core/geom/update/curve.d.ts.map +1 -1
- package/dist/api/core/geom/update/profile.d.ts +36 -12
- package/dist/api/core/geom/update/profile.d.ts.map +1 -1
- package/dist/api/core/io/import/index.d.ts +7 -3
- package/dist/api/core/io/import/index.d.ts.map +1 -1
- package/dist/api/core/math/quat.d.ts +2 -2
- package/dist/api/core/math/quat.d.ts.map +1 -1
- package/dist/api/core/math/vec3.d.ts +15 -15
- package/dist/api/core/math/vec3.d.ts.map +1 -1
- package/dist/api/core/storeys/index.d.ts +5 -0
- package/dist/api/core/storeys/index.d.ts.map +1 -1
- package/dist/api/design/boolean/index.d.ts +20 -4
- package/dist/api/design/boolean/index.d.ts.map +1 -1
- package/dist/api/design/create/bulk-items.d.ts +88 -17
- package/dist/api/design/create/bulk-items.d.ts.map +1 -1
- package/dist/api/design/create/index.d.ts +146 -59
- package/dist/api/design/create/index.d.ts.map +1 -1
- package/dist/api/design/create/opening-fields.d.ts +18 -6
- package/dist/api/design/create/opening-fields.d.ts.map +1 -1
- package/dist/api/design/delete/index.d.ts +14 -7
- package/dist/api/design/delete/index.d.ts.map +1 -1
- package/dist/api/design/dimensions.d.ts +12 -4
- package/dist/api/design/dimensions.d.ts.map +1 -1
- package/dist/api/design/doors/index.d.ts +37 -0
- package/dist/api/design/doors/index.d.ts.map +1 -1
- package/dist/api/design/edit/index.d.ts +7 -3
- package/dist/api/design/edit/index.d.ts.map +1 -1
- package/dist/api/design/family.d.ts +5 -1
- package/dist/api/design/family.d.ts.map +1 -1
- package/dist/api/design/index.d.ts +1 -0
- package/dist/api/design/index.d.ts.map +1 -1
- package/dist/api/design/lock.d.ts +3 -0
- package/dist/api/design/lock.d.ts.map +1 -1
- package/dist/api/design/opening-placement.d.ts +135 -0
- package/dist/api/design/opening-placement.d.ts.map +1 -0
- package/dist/api/design/transform/index.d.ts +28 -8
- package/dist/api/design/transform/index.d.ts.map +1 -1
- package/dist/api/design/windows/index.d.ts +23 -0
- package/dist/api/design/windows/index.d.ts.map +1 -1
- package/dist/api/entity/space.d.ts +30 -6
- package/dist/api/entity/space.d.ts.map +1 -1
- package/dist/api/entity/story.d.ts +4 -0
- package/dist/api/entity/story.d.ts.map +1 -1
- package/dist/api/presentation/drawings.d.ts +1 -1
- package/dist/api/presentation/views.d.ts +5 -1
- package/dist/api/presentation/views.d.ts.map +1 -1
- package/dist/handles.d.ts +8 -0
- package/dist/handles.d.ts.map +1 -1
- package/dist/index.cjs +2510 -2427
- package/dist/index.cjs.map +1 -1
- package/dist/index.js +2506 -2427
- package/dist/index.js.map +1 -1
- package/package.json +13 -13
- package/src/api/core/camera/index.ts +9 -7
- package/src/api/core/comment/index.ts +3 -3
- package/src/api/core/geom/create/index.ts +25 -25
- package/src/api/core/geom/query/circle.ts +11 -11
- package/src/api/core/geom/query/contour.ts +7 -6
- package/src/api/core/geom/query/curve.ts +25 -25
- package/src/api/core/geom/query/profile.ts +7 -6
- package/src/api/core/geom/update/contour.ts +12 -11
- package/src/api/core/geom/update/curve.ts +5 -5
- package/src/api/core/geom/update/profile.ts +12 -11
- package/src/api/core/io/import/index.ts +3 -2
- package/src/api/core/math/quat.ts +2 -2
- package/src/api/core/math/vec3.ts +16 -16
- package/src/api/core/storeys/index.ts +5 -0
- package/src/api/design/boolean/index.ts +2 -2
- package/src/api/design/create/bulk-items.ts +11 -3
- package/src/api/design/create/index.ts +46 -46
- package/src/api/design/create/opening-fields.ts +7 -7
- package/src/api/design/delete/index.ts +14 -7
- package/src/api/design/dimensions.ts +5 -4
- package/src/api/design/doors/index.ts +43 -0
- package/src/api/design/edit/index.ts +3 -3
- package/src/api/design/family.ts +2 -1
- package/src/api/design/index.ts +1 -0
- package/src/api/design/lock.ts +6 -0
- package/src/api/design/opening-placement.ts +79 -0
- package/src/api/design/transform/index.ts +15 -7
- package/src/api/design/windows/index.ts +29 -0
- package/src/api/entity/space.ts +5 -4
- package/src/api/entity/story.ts +4 -0
- package/src/api/presentation/views.ts +7 -2
- package/src/handles.ts +11 -0
- package/test/handles.test.mjs +36 -0
|
@@ -8,6 +8,7 @@ import {
|
|
|
8
8
|
CurveHandle,
|
|
9
9
|
ProfileHandle,
|
|
10
10
|
Vec3Handle,
|
|
11
|
+
Vec3Input,
|
|
11
12
|
} from "../../../handles"
|
|
12
13
|
import { PluginGridStyleOptions } from "./grids"
|
|
13
14
|
import { PluginGraphicsLineStyleId } from "../../presentation/graphics"
|
|
@@ -130,7 +131,7 @@ export abstract class PluginDesignCreateApi {
|
|
|
130
131
|
contour: ContourHandle,
|
|
131
132
|
height: number,
|
|
132
133
|
label?: string,
|
|
133
|
-
position?:
|
|
134
|
+
position?: Vec3Input,
|
|
134
135
|
spaceType?: PluginSpaceType,
|
|
135
136
|
massType?: PluginMassType,
|
|
136
137
|
departmentId?: PluginDepartmentId,
|
|
@@ -165,7 +166,7 @@ export abstract class PluginDesignCreateApi {
|
|
|
165
166
|
contour: ContourHandle,
|
|
166
167
|
height: number,
|
|
167
168
|
label?: string,
|
|
168
|
-
position?:
|
|
169
|
+
position?: Vec3Input,
|
|
169
170
|
massType?: PluginMassType,
|
|
170
171
|
): PluginApiReturn<ComponentHandle>
|
|
171
172
|
|
|
@@ -288,7 +289,7 @@ export abstract class PluginDesignCreateApi {
|
|
|
288
289
|
*/
|
|
289
290
|
public abstract floor(
|
|
290
291
|
...args:
|
|
291
|
-
| [contour: ContourHandle, thickness: number, position?:
|
|
292
|
+
| [contour: ContourHandle, thickness: number, position?: Vec3Input]
|
|
292
293
|
| [contour: ContourHandle, options: PluginFamilyFloorOptions]
|
|
293
294
|
): PluginApiReturn<ComponentHandle[]>
|
|
294
295
|
|
|
@@ -422,10 +423,10 @@ export abstract class PluginDesignCreateApi {
|
|
|
422
423
|
public abstract column(
|
|
423
424
|
...args:
|
|
424
425
|
| [
|
|
425
|
-
position:
|
|
426
|
+
position: Vec3Input,
|
|
426
427
|
crossSection: ContourHandle,
|
|
427
428
|
height: number,
|
|
428
|
-
directionUp?:
|
|
429
|
+
directionUp?: Vec3Input,
|
|
429
430
|
]
|
|
430
431
|
| [axis: LineHandle, options: PluginFamilyPlacement]
|
|
431
432
|
): PluginApiReturn<ComponentHandle>
|
|
@@ -472,7 +473,7 @@ export abstract class PluginDesignCreateApi {
|
|
|
472
473
|
*/
|
|
473
474
|
public abstract beam(
|
|
474
475
|
...args:
|
|
475
|
-
| [section: ContourHandle, length: number, direction?:
|
|
476
|
+
| [section: ContourHandle, length: number, direction?: Vec3Input]
|
|
476
477
|
| [axis: LineHandle, options: PluginFamilyPlacement]
|
|
477
478
|
): PluginApiReturn<ComponentHandle>
|
|
478
479
|
|
|
@@ -496,10 +497,10 @@ export abstract class PluginDesignCreateApi {
|
|
|
496
497
|
* single undo entry. The storey must already exist
|
|
497
498
|
* (`core.storeys.create` first). Default: geometry-derived — a profile
|
|
498
499
|
* drawn at y = 0 lands on storey 1; the ACTIVE storey is NOT consulted.
|
|
499
|
-
* @param topProfiles -
|
|
500
|
-
*
|
|
501
|
-
*
|
|
502
|
-
*
|
|
500
|
+
* @param topProfiles - Top edge per curve of `profile` (same order). Current
|
|
501
|
+
* hosts build walls with one height: any non-null entry is refused with
|
|
502
|
+
* `PRECONDITION_FAILED` ("sloped or stepped tops are not supported") and
|
|
503
|
+
* nothing is created. Pass `null` entries or omit it.
|
|
503
504
|
* @returns a {@linkcode ComponentHandle}`[]` (one per wall), in profile order
|
|
504
505
|
* @throws if the profile is empty, `wallType` names no wall type in the
|
|
505
506
|
* project, `storey` does not exist, `topProfiles` has more entries than the
|
|
@@ -513,9 +514,6 @@ export abstract class PluginDesignCreateApi {
|
|
|
513
514
|
* @examplePrompt Add walls with mitred corners along the path
|
|
514
515
|
* @examplePrompt Draw brick walls with plaster along this outline
|
|
515
516
|
* @examplePrompt Build the perimeter in exposed concrete walls
|
|
516
|
-
* @examplePrompt Create a raked wall that slopes from 3m to 5m
|
|
517
|
-
* @examplePrompt Build a gable end wall with the ridge in the middle
|
|
518
|
-
* @examplePrompt Draw a wall with a sloped top edge
|
|
519
517
|
*
|
|
520
518
|
* # Example
|
|
521
519
|
* ```ts
|
|
@@ -531,13 +529,6 @@ export abstract class PluginDesignCreateApi {
|
|
|
531
529
|
* const brickWalls = await snaptrude.design.create.walls(
|
|
532
530
|
* centerlines, 3, undefined, brick.label,
|
|
533
531
|
* )
|
|
534
|
-
* // …a raked wall (3m at the start, 5m at the end) on a single centerline:
|
|
535
|
-
* const run = await snaptrude.core.geom.create.profileFromCurves([
|
|
536
|
-
* await snaptrude.core.geom.create.line(await v.new(0, 0, 10), await v.new(8, 0, 10)),
|
|
537
|
-
* ])
|
|
538
|
-
* const [raked] = await snaptrude.design.create.walls(run, undefined, 0.2, undefined, undefined, [
|
|
539
|
-
* [{ along: 0, height: 3 }, { along: 1, height: 5 }],
|
|
540
|
-
* ])
|
|
541
532
|
* ```
|
|
542
533
|
*
|
|
543
534
|
* @performance For MORE THAN ONE run, call `design.create.wallRuns(items[])` — one
|
|
@@ -560,8 +551,9 @@ export abstract class PluginDesignCreateApi {
|
|
|
560
551
|
* item's profile chain, mitred at shared endpoints. Junctions resolve within a
|
|
561
552
|
* run, not between runs. Each item carries its own
|
|
562
553
|
* dimensions, `wallType` and `storey`, so a single call can build a whole
|
|
563
|
-
* floor plate or several storeys at once.
|
|
564
|
-
*
|
|
554
|
+
* floor plate or several storeys at once. Walls have one height: a non-null
|
|
555
|
+
* `topProfiles` entry is refused with `PRECONDITION_FAILED` (`details.itemIndex`
|
|
556
|
+
* names the item) and nothing is created. Validate-all-or-throw;
|
|
565
557
|
* one command.
|
|
566
558
|
*
|
|
567
559
|
* @param items - One {@linkcode PluginCreateWallRunItem} per run to create
|
|
@@ -582,7 +574,6 @@ export abstract class PluginDesignCreateApi {
|
|
|
582
574
|
* @examplePrompt Bulk create wall runs from these centerlines
|
|
583
575
|
* @examplePrompt Create the walls for both storeys in a single undo step
|
|
584
576
|
* @examplePrompt Turn these polylines into 200mm brick walls together
|
|
585
|
-
* @examplePrompt Import these raked walls with their top profiles in one go
|
|
586
577
|
*
|
|
587
578
|
* @performance Bulk creator — the whole batch is ONE host round-trip and ONE undo
|
|
588
579
|
* entry. Always prefer this over calling `design.create.walls` in a loop: build the
|
|
@@ -603,9 +594,6 @@ export abstract class PluginDesignCreateApi {
|
|
|
603
594
|
* const [groundWalls, upperWalls] = await snaptrude.design.create.wallRuns([
|
|
604
595
|
* { profile: ground, height: 3, thickness: 0.2 },
|
|
605
596
|
* { profile: upper, height: 3, storey: 2 },
|
|
606
|
-
* // one gable wall: 3m at both ends, 5m ridge in the middle
|
|
607
|
-
* { profile: upper, thickness: 0.2, storey: 3,
|
|
608
|
-
* topProfiles: [[{ along: 0, height: 3 }, { along: 0.5, height: 5 }, { along: 1, height: 3 }]] },
|
|
609
597
|
* ])
|
|
610
598
|
* console.log(groundWalls.length, "walls on the ground floor")
|
|
611
599
|
* ```
|
|
@@ -649,7 +637,7 @@ export abstract class PluginDesignCreateApi {
|
|
|
649
637
|
*/
|
|
650
638
|
public abstract staircase(
|
|
651
639
|
preset: PluginStaircasePreset,
|
|
652
|
-
position:
|
|
640
|
+
position: Vec3Input,
|
|
653
641
|
label?: string,
|
|
654
642
|
structureId?: string,
|
|
655
643
|
level?: string,
|
|
@@ -740,7 +728,7 @@ export abstract class PluginDesignCreateApi {
|
|
|
740
728
|
spacingY: number,
|
|
741
729
|
options?: {
|
|
742
730
|
angle?: number
|
|
743
|
-
center?:
|
|
731
|
+
center?: Vec3Input
|
|
744
732
|
} & PluginGridStyleOptions,
|
|
745
733
|
): PluginApiReturn<ComponentHandle>
|
|
746
734
|
|
|
@@ -895,7 +883,7 @@ export abstract class PluginDesignCreateApi {
|
|
|
895
883
|
*/
|
|
896
884
|
public abstract furniture(
|
|
897
885
|
catalogId: string,
|
|
898
|
-
position:
|
|
886
|
+
position: Vec3Input,
|
|
899
887
|
options?: { label?: string; createNewSourceMesh?: boolean },
|
|
900
888
|
angleInDegrees?: number,
|
|
901
889
|
): PluginApiReturn<ComponentHandle>
|
|
@@ -1008,14 +996,14 @@ export abstract class PluginDesignCreateApi {
|
|
|
1008
996
|
public abstract door(
|
|
1009
997
|
familyId: string,
|
|
1010
998
|
hostWall: ComponentHandle,
|
|
1011
|
-
position:
|
|
999
|
+
position: Vec3Input,
|
|
1012
1000
|
options?: {
|
|
1013
1001
|
label?: string
|
|
1014
|
-
hinge?:
|
|
1002
|
+
hinge?: Vec3Input
|
|
1015
1003
|
version?: number
|
|
1016
1004
|
values?: Record<string, number | string>
|
|
1017
1005
|
},
|
|
1018
|
-
facing?:
|
|
1006
|
+
facing?: Vec3Input,
|
|
1019
1007
|
): PluginApiReturn<ComponentHandle>
|
|
1020
1008
|
|
|
1021
1009
|
/**
|
|
@@ -1047,6 +1035,12 @@ export abstract class PluginDesignCreateApi {
|
|
|
1047
1035
|
* @examplePrompt Put three doors on this wall in a single undo step
|
|
1048
1036
|
* @examplePrompt Add all the doors for this floor plan together
|
|
1049
1037
|
*
|
|
1038
|
+
* A width/height (top-level, or under the family's own keys in `values`) on a family that
|
|
1039
|
+
* takes its size from its Type while Custom Sizes is off is never dropped: the Type within
|
|
1040
|
+
* 25 mm is chosen, else Custom Sizes is turned on and that size is built, leaving the Type
|
|
1041
|
+
* label stale. `design.doors.checkPlacement` reports which as `sizing`; `customSizes: "No"`
|
|
1042
|
+
* with a size no Type matches is refused.
|
|
1043
|
+
*
|
|
1050
1044
|
* @performance Bulk creator — the whole batch is ONE host round-trip and ONE undo
|
|
1051
1045
|
* entry. Always prefer this over
|
|
1052
1046
|
* calling `design.create.door` in a loop: build the full `items[]` array first
|
|
@@ -1112,14 +1106,14 @@ export abstract class PluginDesignCreateApi {
|
|
|
1112
1106
|
public abstract window(
|
|
1113
1107
|
familyId: string,
|
|
1114
1108
|
hostWall: ComponentHandle,
|
|
1115
|
-
position:
|
|
1109
|
+
position: Vec3Input,
|
|
1116
1110
|
options?: {
|
|
1117
1111
|
label?: string
|
|
1118
|
-
hinge?:
|
|
1112
|
+
hinge?: Vec3Input
|
|
1119
1113
|
version?: number
|
|
1120
1114
|
values?: Record<string, number | string>
|
|
1121
1115
|
},
|
|
1122
|
-
facing?:
|
|
1116
|
+
facing?: Vec3Input,
|
|
1123
1117
|
): PluginApiReturn<ComponentHandle>
|
|
1124
1118
|
|
|
1125
1119
|
/**
|
|
@@ -1152,6 +1146,12 @@ export abstract class PluginDesignCreateApi {
|
|
|
1152
1146
|
* @examplePrompt Put four windows on this wall in a single undo step
|
|
1153
1147
|
* @examplePrompt Add all the windows with a 0.9m sill height together
|
|
1154
1148
|
*
|
|
1149
|
+
* A width/height (top-level, or under the family's own keys in `values`) on a family that
|
|
1150
|
+
* takes its size from its Type while Custom Sizes is off is never dropped: the Type within
|
|
1151
|
+
* 25 mm is chosen, else Custom Sizes is turned on and that size is built, leaving the Type
|
|
1152
|
+
* label stale. `design.windows.checkPlacement` reports which as `sizing`; `customSizes: "No"`
|
|
1153
|
+
* with a size no Type matches is refused.
|
|
1154
|
+
*
|
|
1155
1155
|
* @performance Bulk creator — the whole batch is ONE host round-trip and ONE undo
|
|
1156
1156
|
* entry. Always prefer this over
|
|
1157
1157
|
* calling `design.create.window` in a loop: build the full `items[]` array first
|
|
@@ -1446,7 +1446,7 @@ export abstract class PluginDesignCreateApi {
|
|
|
1446
1446
|
*/
|
|
1447
1447
|
public abstract copy(
|
|
1448
1448
|
components: ComponentHandle[],
|
|
1449
|
-
displacement:
|
|
1449
|
+
displacement: Vec3Input,
|
|
1450
1450
|
options?: { count?: number; mode?: PluginCopyMode },
|
|
1451
1451
|
): PluginApiReturn<ComponentHandle[]>
|
|
1452
1452
|
|
|
@@ -1669,7 +1669,7 @@ export const PluginDesignCreateSpaceArgs = z.object({
|
|
|
1669
1669
|
contour: ContourHandle,
|
|
1670
1670
|
height: z.number(),
|
|
1671
1671
|
label: z.string().optional(),
|
|
1672
|
-
position:
|
|
1672
|
+
position: Vec3Input.optional(),
|
|
1673
1673
|
spaceType: PluginSpaceType.optional(),
|
|
1674
1674
|
massType: PluginMassType.optional(),
|
|
1675
1675
|
departmentId: PluginDepartmentId.optional(),
|
|
@@ -1700,7 +1700,7 @@ export const PluginDesignCreateMassArgs = z.object({
|
|
|
1700
1700
|
contour: ContourHandle,
|
|
1701
1701
|
height: z.number(),
|
|
1702
1702
|
label: z.string().optional(),
|
|
1703
|
-
position:
|
|
1703
|
+
position: Vec3Input.optional(),
|
|
1704
1704
|
massType: PluginMassType.optional(),
|
|
1705
1705
|
})
|
|
1706
1706
|
export type PluginDesignCreateMassArgs = z.infer<
|
|
@@ -1767,7 +1767,7 @@ export type PluginDesignCreateSlabArgs = z.infer<
|
|
|
1767
1767
|
export const PluginDesignCreateFloorArgs = z.object({
|
|
1768
1768
|
contour: ContourHandle,
|
|
1769
1769
|
thickness: z.number(),
|
|
1770
|
-
position:
|
|
1770
|
+
position: Vec3Input.optional(),
|
|
1771
1771
|
})
|
|
1772
1772
|
export type PluginDesignCreateFloorArgs = z.infer<
|
|
1773
1773
|
typeof PluginDesignCreateFloorArgs
|
|
@@ -1830,10 +1830,10 @@ export type PluginDesignCreateCeilingArgs = z.infer<
|
|
|
1830
1830
|
* | `directionUp` | {@linkcode Vec3Handle}? | Up axis (default world up) |
|
|
1831
1831
|
*/
|
|
1832
1832
|
export const PluginDesignCreateColumnArgs = z.object({
|
|
1833
|
-
position:
|
|
1833
|
+
position: Vec3Input,
|
|
1834
1834
|
crossSection: ContourHandle,
|
|
1835
1835
|
height: z.number(),
|
|
1836
|
-
directionUp:
|
|
1836
|
+
directionUp: Vec3Input.optional(),
|
|
1837
1837
|
})
|
|
1838
1838
|
export type PluginDesignCreateColumnArgs = z.infer<
|
|
1839
1839
|
typeof PluginDesignCreateColumnArgs
|
|
@@ -1855,7 +1855,7 @@ export type PluginDesignCreateColumnArgs = z.infer<
|
|
|
1855
1855
|
export const PluginDesignCreateBeamArgs = z.object({
|
|
1856
1856
|
section: ContourHandle,
|
|
1857
1857
|
length: z.number(),
|
|
1858
|
-
direction:
|
|
1858
|
+
direction: Vec3Input.optional(),
|
|
1859
1859
|
})
|
|
1860
1860
|
export type PluginDesignCreateBeamArgs = z.infer<
|
|
1861
1861
|
typeof PluginDesignCreateBeamArgs
|
|
@@ -1910,7 +1910,7 @@ export type PluginDesignCreateWallsArgs = z.infer<
|
|
|
1910
1910
|
*/
|
|
1911
1911
|
export const PluginDesignCreateStaircaseArgs = z.object({
|
|
1912
1912
|
preset: PluginStaircasePreset,
|
|
1913
|
-
position:
|
|
1913
|
+
position: Vec3Input,
|
|
1914
1914
|
label: z.string().optional(),
|
|
1915
1915
|
structureId: z.string().optional(),
|
|
1916
1916
|
level: z.string().optional(),
|
|
@@ -1937,7 +1937,7 @@ export type PluginDesignCreateStaircaseArgs = z.infer<
|
|
|
1937
1937
|
*/
|
|
1938
1938
|
export const PluginDesignCreateFurnitureArgs = z.object({
|
|
1939
1939
|
catalogId: z.string().min(1),
|
|
1940
|
-
position:
|
|
1940
|
+
position: Vec3Input,
|
|
1941
1941
|
label: z.string().optional(),
|
|
1942
1942
|
createNewSourceMesh: z.boolean().optional(),
|
|
1943
1943
|
angleInDegrees: z.number().optional(),
|
|
@@ -2195,7 +2195,7 @@ export type PluginCopyMode = z.infer<typeof PluginCopyMode>
|
|
|
2195
2195
|
*/
|
|
2196
2196
|
export const PluginDesignCreateCopyArgs = z.object({
|
|
2197
2197
|
components: z.array(ComponentHandle).min(1),
|
|
2198
|
-
displacement:
|
|
2198
|
+
displacement: Vec3Input,
|
|
2199
2199
|
count: z.number().int().positive().optional(),
|
|
2200
2200
|
mode: PluginCopyMode.optional(),
|
|
2201
2201
|
})
|
|
@@ -2228,7 +2228,7 @@ export const PluginCreateSpaceItem = z.object({
|
|
|
2228
2228
|
contour: ContourHandle,
|
|
2229
2229
|
height: z.number(),
|
|
2230
2230
|
label: z.string().optional(),
|
|
2231
|
-
position:
|
|
2231
|
+
position: Vec3Input.optional(),
|
|
2232
2232
|
spaceType: PluginSpaceType.optional(),
|
|
2233
2233
|
massType: PluginMassType.optional(),
|
|
2234
2234
|
departmentId: PluginDepartmentId.optional(),
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import * as z from "zod"
|
|
2
|
-
import { ComponentHandle,
|
|
2
|
+
import { ComponentHandle, Vec3Input } from "../../../handles"
|
|
3
3
|
|
|
4
4
|
/**
|
|
5
5
|
* The shared field bag every hosted opening (door / window) carries — used by
|
|
@@ -17,9 +17,9 @@ import { ComponentHandle, Vec3Handle } from "../../../handles"
|
|
|
17
17
|
* | `version` | `number`? | Exact family version; newest known by default |
|
|
18
18
|
* | `values` | `Record<string, number \| string>`? | Authored instance parameters; numeric lengths use Snaptrude units |
|
|
19
19
|
* | `hostWall` | {@linkcode ComponentHandle} | The wall to host the opening |
|
|
20
|
-
* | `position` | {@linkcode
|
|
21
|
-
* | `facing` | {@linkcode
|
|
22
|
-
* | `hinge` | {@linkcode
|
|
20
|
+
* | `position` | {@linkcode Vec3Input} | World point projected onto the wall (a vec3 handle or a plain `{ x, y, z }`) |
|
|
21
|
+
* | `facing` | {@linkcode Vec3Input}? | World point on the side of the wall the opening swings open to (default engine-chosen) |
|
|
22
|
+
* | `hinge` | {@linkcode Vec3Input}? | World point near the hinged jamb; requires the recipe's hand parameter |
|
|
23
23
|
* | `label` | `string`? | Instance name (optional) |
|
|
24
24
|
* | `width` | `number`? | Sets the declared width parameter, not the opening's evaluated envelope |
|
|
25
25
|
* | `height` | `number`? | Sets the declared height parameter |
|
|
@@ -31,9 +31,9 @@ export const PluginOpeningBaseOptions = {
|
|
|
31
31
|
.record(z.string(), z.union([z.number().finite(), z.string()]))
|
|
32
32
|
.optional(),
|
|
33
33
|
hostWall: ComponentHandle,
|
|
34
|
-
position:
|
|
35
|
-
facing:
|
|
36
|
-
hinge:
|
|
34
|
+
position: Vec3Input,
|
|
35
|
+
facing: Vec3Input.optional(),
|
|
36
|
+
hinge: Vec3Input.optional(),
|
|
37
37
|
label: z.string().optional(),
|
|
38
38
|
width: z.number().finite().positive().optional(),
|
|
39
39
|
height: z.number().finite().positive().optional(),
|
|
@@ -8,7 +8,7 @@ import { PluginDesignChangeResult } from "../lock"
|
|
|
8
8
|
*
|
|
9
9
|
* | Property | Type | Description |
|
|
10
10
|
* |---|---|---|
|
|
11
|
-
* | `components` | {@linkcode ComponentHandle}`[]` | Entities to delete.
|
|
11
|
+
* | `components` | {@linkcode ComponentHandle}`[]` | Entities to delete. Handles that no longer resolve are skipped and returned as `missing`; the call rejects only when none resolve. |
|
|
12
12
|
*
|
|
13
13
|
* `.min(1)` is deliberately stricter than the shipped `PluginDesignLockArgs`
|
|
14
14
|
* (which allows an empty array) — an empty delete is a caller error, not a no-op.
|
|
@@ -43,12 +43,19 @@ export abstract class PluginDesignDeleteApi {
|
|
|
43
43
|
* entry, exactly as the editor's Delete key does — see `design.dimensions`. They are
|
|
44
44
|
* NOT listed in `affected`, which reports component handles only.
|
|
45
45
|
*
|
|
46
|
-
* @param components - Entities to delete.
|
|
47
|
-
*
|
|
48
|
-
*
|
|
49
|
-
*
|
|
50
|
-
*
|
|
51
|
-
*
|
|
46
|
+
* @param components - Entities to delete. A handle that no longer resolves (already
|
|
47
|
+
* removed by an earlier edit — a door deleted with its wall, a wall replaced by an
|
|
48
|
+
* opening's re-cut) is skipped, not fatal.
|
|
49
|
+
* @returns `{ affected, cascaded?, missing?, rejected? }`: the entities you asked to delete
|
|
50
|
+
* (echoed host-side — the engine returns no ids); `cascaded`, the derived walls/floors/slabs
|
|
51
|
+
* the parametric graph removed with a deleted space; `missing`, handles that no longer
|
|
52
|
+
* resolved and were skipped; `rejected`, handles the engine accepted but left standing
|
|
53
|
+
* (delete them again, one at a time, or report them). Deleted handles are **stale**
|
|
54
|
+
* afterwards: re-resolving one throws `HANDLE_STALE`.
|
|
55
|
+
* @throws `HANDLE_INVALID` when NONE of the supplied handles resolve (nothing is deleted);
|
|
56
|
+
* hosts before Oct 2026 reject the whole call when any handle is gone. `OPERATION_FAILED`
|
|
57
|
+
* when the parametric engine rejects the deletion — the batch is rolled back.
|
|
58
|
+
* `HANDLE_STALE` for a handle the caller held that has since been retired.
|
|
52
59
|
*
|
|
53
60
|
* @examplePrompt Delete the selected objects
|
|
54
61
|
* @examplePrompt Remove these walls from the model
|
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
DimensionHandle,
|
|
6
6
|
Vec3Components,
|
|
7
7
|
Vec3Handle,
|
|
8
|
+
Vec3Input,
|
|
8
9
|
} from "../../handles"
|
|
9
10
|
|
|
10
11
|
/**
|
|
@@ -94,8 +95,8 @@ export abstract class PluginDesignDimensionsApi {
|
|
|
94
95
|
* ```
|
|
95
96
|
*/
|
|
96
97
|
public abstract create(
|
|
97
|
-
from:
|
|
98
|
-
to:
|
|
98
|
+
from: Vec3Input,
|
|
99
|
+
to: Vec3Input,
|
|
99
100
|
anchor: ComponentHandle,
|
|
100
101
|
options?: { anchorTo?: ComponentHandle; offset?: number },
|
|
101
102
|
): PluginApiReturn<DimensionHandle>
|
|
@@ -362,8 +363,8 @@ export type PluginDimensionsChangeResult = z.infer<
|
|
|
362
363
|
* TRANSPORT: positional args — validated host-side as this object.
|
|
363
364
|
*/
|
|
364
365
|
export const PluginDesignDimensionsCreateArgs = z.object({
|
|
365
|
-
from:
|
|
366
|
-
to:
|
|
366
|
+
from: Vec3Input,
|
|
367
|
+
to: Vec3Input,
|
|
367
368
|
anchor: ComponentHandle,
|
|
368
369
|
anchorTo: ComponentHandle.optional(),
|
|
369
370
|
offset: z.number().finite().optional(),
|
|
@@ -2,6 +2,10 @@ import * as z from "zod"
|
|
|
2
2
|
import { PluginApiReturn } from "../../../types"
|
|
3
3
|
import { ComponentHandle } from "../../../handles"
|
|
4
4
|
import { PluginDesignChangeResult } from "../lock"
|
|
5
|
+
import type {
|
|
6
|
+
PluginOpeningPlacementArgs,
|
|
7
|
+
PluginOpeningPlacementResult,
|
|
8
|
+
} from "../opening-placement"
|
|
5
9
|
|
|
6
10
|
/**
|
|
7
11
|
* `snaptrude.design.doors` — door-specific reads + edits. Creation lives at
|
|
@@ -22,6 +26,33 @@ import { PluginDesignChangeResult } from "../lock"
|
|
|
22
26
|
export abstract class PluginDesignDoorsApi {
|
|
23
27
|
constructor() {}
|
|
24
28
|
|
|
29
|
+
/**
|
|
30
|
+
* Trial the native host fit and geometry rebuild, then restore the model without publishing commands.
|
|
31
|
+
* The first result uses the creation options; subsequent results use candidateWidths in input order.
|
|
32
|
+
* Widths are authored parameters, not physical envelopes or a guaranteed maximum width.
|
|
33
|
+
* No catalog save, history entry or model persistence occurs. Rerun after model edits.
|
|
34
|
+
* A failed fit leaves cut unverified. Family-host cuts are also unverified: their rebuild
|
|
35
|
+
* cannot supply a reversible, authoritative trial result. Material clearance checks evaluated
|
|
36
|
+
* parts against physical neighbours across hosts. The intended host uses native fit/cut checks.
|
|
37
|
+
* Creation repeats clearance immediately before placement; this report grants no later approval.
|
|
38
|
+
* Editing permission is required; locked hosts and an active opening tool reject.
|
|
39
|
+
* It does not say which room the door opens into: read `opensInto` from
|
|
40
|
+
* `design.validation.access()` after placement (see {@linkcode getSwingDirection}).
|
|
41
|
+
* A requested width/height on a family sized by its Type (Custom Sizes off) picks the Type
|
|
42
|
+
* within 25 mm, else turns Custom Sizes on; each result's `sizing` says which. Creation
|
|
43
|
+
* (`design.create.door(s)`) applies the same rule, so the size you pass is the size built.
|
|
44
|
+
* @param options Door creation options and up to 12 alternative widths; numeric lengths use SU.
|
|
45
|
+
* @returns Separate fit/cut/clearance evidence, evaluated bounds and explicit limitations.
|
|
46
|
+
* @examplePrompt Check which door widths fit this host without placing a door
|
|
47
|
+
* @example
|
|
48
|
+
* const result = await snaptrude.design.doors.checkPlacement({
|
|
49
|
+
* familyId, version, hostWall, position, width: 3.5, candidateWidths: [3, 2.5],
|
|
50
|
+
* })
|
|
51
|
+
*/
|
|
52
|
+
public abstract checkPlacement(
|
|
53
|
+
options: PluginOpeningPlacementArgs,
|
|
54
|
+
): PluginApiReturn<PluginOpeningPlacementResult>
|
|
55
|
+
|
|
25
56
|
/**
|
|
26
57
|
* Get the type name of a door — the label that identifies which kind of door
|
|
27
58
|
* the instance is, as shown in its properties.
|
|
@@ -163,6 +194,12 @@ export abstract class PluginDesignDoorsApi {
|
|
|
163
194
|
* Read the saved hand parameter. left means local -X; right means local +X.
|
|
164
195
|
* Returns null when the recipe does not declare that control.
|
|
165
196
|
*
|
|
197
|
+
* Hand is the hinge side, not the room the leaf swings into. For that, read
|
|
198
|
+
* `(await design.validation.access()).topology.rooms[].doors[].opensInto`: a
|
|
199
|
+
* converted room or `"outside"`. A door whose wall is not a room edge is listed
|
|
200
|
+
* in `topology.unresolvedDoors` instead. To make it open into the other room,
|
|
201
|
+
* call {@linkcode mirror} (axis `x`) and read access again.
|
|
202
|
+
*
|
|
166
203
|
* @param door The door to query
|
|
167
204
|
* @returns `'left'` / `'right'`, or `null` if indeterminate
|
|
168
205
|
*
|
|
@@ -170,12 +207,16 @@ export abstract class PluginDesignDoorsApi {
|
|
|
170
207
|
* @examplePrompt Is the selected door left-handed or right-handed?
|
|
171
208
|
* @examplePrompt Check the hinge side of this door
|
|
172
209
|
* @examplePrompt Does the entrance door open to the left or the right?
|
|
210
|
+
* @examplePrompt Which room does this door open into?
|
|
173
211
|
*
|
|
174
212
|
* # Example
|
|
175
213
|
* ```ts
|
|
176
214
|
* const [door] = await snaptrude.design.query.listDoors({ isSelected: true })
|
|
177
215
|
* const swing = await snaptrude.design.doors.getSwingDirection(door)
|
|
178
216
|
* if (swing) console.log("opens as a", swing, "hand door")
|
|
217
|
+
* // Which room it opens into
|
|
218
|
+
* const { topology } = await snaptrude.design.validation.access()
|
|
219
|
+
* const side = topology.rooms.flatMap((r) => r.doors).find((d) => d.door === door)?.opensInto
|
|
179
220
|
* ```
|
|
180
221
|
*/
|
|
181
222
|
public abstract getSwingDirection(
|
|
@@ -188,6 +229,8 @@ export abstract class PluginDesignDoorsApi {
|
|
|
188
229
|
* Axis y rejects. No mesh reflection occurs. Recipes use outputs.swingSide
|
|
189
230
|
* (1 or -1) for the adjoining room's floor ownership. A door between two
|
|
190
231
|
* room floors requires this output; a missing or invalid report rejects the cut.
|
|
232
|
+
* The same side decides `opensInto` in `design.validation.access()`; read it
|
|
233
|
+
* there to confirm which room the door now opens into.
|
|
191
234
|
*
|
|
192
235
|
* @param door The door to mirror
|
|
193
236
|
* @param axis Reflection axis (optional; default `'x'` — the swing-flip axis; `'z'` — the hinge-jamb axis)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import * as z from "zod"
|
|
2
2
|
import { PluginApiReturn } from "../../../types"
|
|
3
|
-
import { ComponentHandle,
|
|
3
|
+
import { ComponentHandle, Vec3Input } from "../../../handles"
|
|
4
4
|
import { OffsetSplitOutcome } from "../shared"
|
|
5
5
|
|
|
6
6
|
/**
|
|
@@ -41,7 +41,7 @@ export abstract class PluginDesignEditApi {
|
|
|
41
41
|
public abstract offsetSplit(
|
|
42
42
|
component: ComponentHandle,
|
|
43
43
|
offsetDistance: number,
|
|
44
|
-
options?: { profilePickPoint?:
|
|
44
|
+
options?: { profilePickPoint?: Vec3Input },
|
|
45
45
|
): PluginApiReturn<OffsetSplitOutcome>
|
|
46
46
|
}
|
|
47
47
|
|
|
@@ -49,6 +49,6 @@ export abstract class PluginDesignEditApi {
|
|
|
49
49
|
export const PluginDesignOffsetSplitArgs = z.object({
|
|
50
50
|
component: ComponentHandle,
|
|
51
51
|
offsetDistance: z.number(),
|
|
52
|
-
profilePickPoint:
|
|
52
|
+
profilePickPoint: Vec3Input.optional(),
|
|
53
53
|
})
|
|
54
54
|
export type PluginDesignOffsetSplitArgs = z.infer<typeof PluginDesignOffsetSplitArgs>
|
package/src/api/design/family.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
ComponentHandle,
|
|
6
6
|
Vec3Components,
|
|
7
7
|
Vec3Handle,
|
|
8
|
+
Vec3Input,
|
|
8
9
|
} from "../../handles"
|
|
9
10
|
import { NetworkFamilyContract } from "./networks"
|
|
10
11
|
|
|
@@ -1319,7 +1320,7 @@ export type PluginDesignFamilyDeleteArgs = z.infer<
|
|
|
1319
1320
|
export const PluginDesignFamilyPlaceArgs = z.object({
|
|
1320
1321
|
id: z.string().optional(),
|
|
1321
1322
|
version: z.number().int().positive().optional(),
|
|
1322
|
-
position: z.union([
|
|
1323
|
+
position: z.union([Vec3Input, Vec3Components]).optional(),
|
|
1323
1324
|
rotation: z.number().optional(),
|
|
1324
1325
|
values: z.record(z.string(), z.union([z.number(), z.string()])).optional(),
|
|
1325
1326
|
storey: z.number().int().optional(),
|
package/src/api/design/index.ts
CHANGED
package/src/api/design/lock.ts
CHANGED
|
@@ -9,6 +9,12 @@ import { ComponentHandle } from "../../handles"
|
|
|
9
9
|
*/
|
|
10
10
|
export const PluginDesignChangeResult = z.object({
|
|
11
11
|
affected: z.array(ComponentHandle),
|
|
12
|
+
/** Derived BIM (walls/floors/slabs) the parametric engine removed with its host. Delete only. */
|
|
13
|
+
cascaded: z.array(ComponentHandle).optional(),
|
|
14
|
+
/** Handles that no longer resolved when the call ran and were skipped. Delete only. */
|
|
15
|
+
missing: z.array(ComponentHandle).optional(),
|
|
16
|
+
/** Handles the engine accepted but left standing; delete them again or report them. Delete only. */
|
|
17
|
+
rejected: z.array(ComponentHandle).optional(),
|
|
12
18
|
})
|
|
13
19
|
export type PluginDesignChangeResult = z.infer<typeof PluginDesignChangeResult>
|
|
14
20
|
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import * as z from "zod"
|
|
2
|
+
import { PluginOpeningBaseOptions } from "./create/opening-fields"
|
|
3
|
+
|
|
4
|
+
/** Creation options plus bounded alternative widths. Each trial starts from the same model. */
|
|
5
|
+
export const PluginOpeningPlacementArgs = z.object({
|
|
6
|
+
...PluginOpeningBaseOptions,
|
|
7
|
+
sillHeight: z.number().finite().nonnegative().optional(),
|
|
8
|
+
candidateWidths: z.array(z.number().finite().positive()).max(12).optional(),
|
|
9
|
+
})
|
|
10
|
+
export type PluginOpeningPlacementArgs = z.infer<
|
|
11
|
+
typeof PluginOpeningPlacementArgs
|
|
12
|
+
>
|
|
13
|
+
|
|
14
|
+
/** A failed fit leaves the cut unverified: no geometry trial was attempted. */
|
|
15
|
+
export const PluginOpeningPlacementCheck = z.object({
|
|
16
|
+
status: z.enum(["pass", "fail", "unverified"]),
|
|
17
|
+
reason: z.string(),
|
|
18
|
+
})
|
|
19
|
+
|
|
20
|
+
const bounds = z.object({
|
|
21
|
+
min: z.object({ x: z.number().finite(), y: z.number().finite(), z: z.number().finite() }),
|
|
22
|
+
max: z.object({ x: z.number().finite(), y: z.number().finite(), z: z.number().finite() }),
|
|
23
|
+
})
|
|
24
|
+
|
|
25
|
+
/** Fit, cut and material clearance are independent checks, not an accessibility certificate. */
|
|
26
|
+
export const PluginOpeningPlacementResult = z.object({
|
|
27
|
+
units: z.literal("SU"),
|
|
28
|
+
results: z.array(
|
|
29
|
+
z.object({
|
|
30
|
+
requestedWidth: z.number().finite().positive().optional(),
|
|
31
|
+
requestedHeight: z.number().finite().positive().optional(),
|
|
32
|
+
/** Original parameter overrides. Evaluated bounds can differ from these values. */
|
|
33
|
+
requestedValues: z.record(z.string(), z.union([z.number().finite(), z.string()])).optional(),
|
|
34
|
+
/**
|
|
35
|
+
* Present when the family sizes itself from a Type unless Custom Sizes is on, and a width
|
|
36
|
+
* or height was requested. `type`: the Type within 25 mm was chosen (its label stays true).
|
|
37
|
+
* `custom`: none matched, so Custom Sizes was turned on and the requested size is built;
|
|
38
|
+
* `type` then names the Type that no longer describes it. Creation applies the same rule.
|
|
39
|
+
*/
|
|
40
|
+
sizing: z
|
|
41
|
+
.object({
|
|
42
|
+
mode: z.enum(["type", "custom"]),
|
|
43
|
+
typeKey: z.string(),
|
|
44
|
+
type: z.string(),
|
|
45
|
+
note: z.string(),
|
|
46
|
+
})
|
|
47
|
+
.optional(),
|
|
48
|
+
/** World-space bounds of evaluated material parts, never the opening proxy. */
|
|
49
|
+
physicalBounds: bounds.optional(),
|
|
50
|
+
/** Only present when the recipe declares semantic frame anatomy. */
|
|
51
|
+
frameBounds: bounds.optional(),
|
|
52
|
+
/** World enclosure of the authored cut envelope; not frame or clear passage width. */
|
|
53
|
+
roughOpeningBounds: bounds.optional(),
|
|
54
|
+
dimensions: z
|
|
55
|
+
.object({
|
|
56
|
+
width: z.number().finite().positive(),
|
|
57
|
+
height: z.number().finite().positive(),
|
|
58
|
+
thickness: z.number().finite().nonnegative(),
|
|
59
|
+
})
|
|
60
|
+
.optional(),
|
|
61
|
+
fit: PluginOpeningPlacementCheck,
|
|
62
|
+
cut: PluginOpeningPlacementCheck,
|
|
63
|
+
clearance: PluginOpeningPlacementCheck.extend({
|
|
64
|
+
candidatePairs: z.number().int().nonnegative(),
|
|
65
|
+
checkedPairs: z.number().int().nonnegative(),
|
|
66
|
+
obstructions: z.array(z.object({
|
|
67
|
+
entity: z.string(),
|
|
68
|
+
status: z.enum(["fail", "unverified"]),
|
|
69
|
+
reason: z.string(),
|
|
70
|
+
intersectionVolume: z.number().finite().nonnegative().optional(),
|
|
71
|
+
})),
|
|
72
|
+
}),
|
|
73
|
+
}),
|
|
74
|
+
),
|
|
75
|
+
limitations: z.array(z.string()),
|
|
76
|
+
})
|
|
77
|
+
export type PluginOpeningPlacementResult = z.infer<
|
|
78
|
+
typeof PluginOpeningPlacementResult
|
|
79
|
+
>
|