@snaptrude/plugin-core 0.9.15 → 0.9.16-networks-20261009.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 (59) hide show
  1. package/CHANGELOG.md +6 -0
  2. package/dist/api/analysis/daylight.d.ts +5 -5
  3. package/dist/api/analysis/solar.d.ts +2 -2
  4. package/dist/api/core/camera/index.d.ts +418 -0
  5. package/dist/api/core/camera/index.d.ts.map +1 -1
  6. package/dist/api/design/bim.d.ts +209 -0
  7. package/dist/api/design/bim.d.ts.map +1 -0
  8. package/dist/api/design/catalog.d.ts +242 -0
  9. package/dist/api/design/catalog.d.ts.map +1 -0
  10. package/dist/api/design/create/bulk-items.d.ts +40 -21
  11. package/dist/api/design/create/bulk-items.d.ts.map +1 -1
  12. package/dist/api/design/create/index.d.ts +120 -97
  13. package/dist/api/design/create/index.d.ts.map +1 -1
  14. package/dist/api/design/create/opening-fields.d.ts +13 -12
  15. package/dist/api/design/create/opening-fields.d.ts.map +1 -1
  16. package/dist/api/design/doors/index.d.ts +18 -24
  17. package/dist/api/design/doors/index.d.ts.map +1 -1
  18. package/dist/api/design/family.d.ts +576 -12
  19. package/dist/api/design/family.d.ts.map +1 -1
  20. package/dist/api/design/index.d.ts +16 -0
  21. package/dist/api/design/index.d.ts.map +1 -1
  22. package/dist/api/design/networks.d.ts +1703 -0
  23. package/dist/api/design/networks.d.ts.map +1 -0
  24. package/dist/api/design/query/index.d.ts +30 -30
  25. package/dist/api/design/selection/index.d.ts +10 -10
  26. package/dist/api/design/types/index.d.ts +40 -24
  27. package/dist/api/design/types/index.d.ts.map +1 -1
  28. package/dist/api/design/update/index.d.ts +40 -3
  29. package/dist/api/design/update/index.d.ts.map +1 -1
  30. package/dist/api/design/windows/index.d.ts +8 -8
  31. package/dist/api/design/windows/index.d.ts.map +1 -1
  32. package/dist/api/presentation/aiInspiration.d.ts +10 -10
  33. package/dist/api/presentation/index.d.ts +9 -0
  34. package/dist/api/presentation/index.d.ts.map +1 -1
  35. package/dist/api/presentation/walkthroughs.d.ts +1350 -0
  36. package/dist/api/presentation/walkthroughs.d.ts.map +1 -0
  37. package/dist/index.cjs +3262 -2185
  38. package/dist/index.cjs.map +1 -1
  39. package/dist/index.js +3153 -2185
  40. package/dist/index.js.map +1 -1
  41. package/package.json +1 -1
  42. package/scripts/generate-manifest.mjs +5 -0
  43. package/src/api/core/camera/index.ts +400 -1
  44. package/src/api/design/bim.ts +121 -0
  45. package/src/api/design/catalog.ts +128 -0
  46. package/src/api/design/create/bulk-items.ts +23 -16
  47. package/src/api/design/create/index.ts +129 -119
  48. package/src/api/design/create/opening-fields.ts +15 -12
  49. package/src/api/design/doors/index.ts +58 -42
  50. package/src/api/design/family.ts +470 -17
  51. package/src/api/design/index.ts +34 -4
  52. package/src/api/design/networks.ts +607 -0
  53. package/src/api/design/types/index.ts +31 -24
  54. package/src/api/design/update/index.ts +41 -3
  55. package/src/api/design/windows/index.ts +40 -22
  56. package/src/api/presentation/index.ts +9 -0
  57. package/src/api/presentation/walkthroughs.ts +1201 -0
  58. package/api-manifest.full.json +0 -8930
  59. package/api-manifest.json +0 -9318
@@ -1,6 +1,8 @@
1
1
  import * as z from "zod"
2
2
  import { ContourHandle, ProfileHandle, Vec3Handle } from "../../../handles"
3
3
  import { PluginOpeningBaseOptions } from "./opening-fields"
4
+ import { PluginWallType } from "../types"
5
+ import { PluginFamilyValues } from "../catalog"
4
6
 
5
7
  /**
6
8
  * Maximum items per bulk `design.create.*` call. A bounded request keeps
@@ -88,7 +90,7 @@ export type PluginWallTopProfile = z.infer<typeof PluginWallTopProfile>
88
90
  * | `profile` | {@linkcode ProfileHandle} | Ordered curve chain (wall centerlines) |
89
91
  * | `height` | `number`? | Wall height (Snaptrude units, > 0; default engine default) |
90
92
  * | `thickness` | `number`? | Wall thickness (Snaptrude units, > 0; default: `wallType`'s total layer thickness when given, else engine default) |
91
- * | `wallType` | `string`? | Wall type name from `design.types.list("wall")` — layers/material/thickness defaults (default generic) |
93
+ * | `wallType` | {@linkcode PluginWallType}? | Legacy name/id or exact native `{ id, version }` pin from `design.types.list("wall")` (default generic) |
92
94
  * | `storey` | `number`? (int) | Target storey (must exist) — the run's walls are assigned + lifted to its base in the same undo entry (default: geometry-derived) |
93
95
  * | `topProfiles` | ({@linkcode PluginWallTopProfile} \| `null`)[]? | Top edge per curve of `profile`, same order; a `null` or missing entry keeps that wall flat at `height`. Raked / gabled walls (straight curves only) |
94
96
  */
@@ -96,9 +98,11 @@ export const PluginCreateWallRunItem = z.object({
96
98
  profile: ProfileHandle,
97
99
  height: z.number().optional(),
98
100
  thickness: z.number().optional(),
99
- wallType: z.string().min(1).optional(),
101
+ wallType: PluginWallType.optional(),
100
102
  storey: z.number().int().optional(),
101
103
  topProfiles: z.array(PluginWallTopProfile.nullable()).optional(),
104
+ /** Optional family overrides in mm/degrees. Host length/height stay geometry inputs. */
105
+ values: PluginFamilyValues.optional(),
102
106
  })
103
107
  export type PluginCreateWallRunItem = z.infer<typeof PluginCreateWallRunItem>
104
108
 
@@ -143,22 +147,23 @@ export type PluginCreateFloorItems = z.infer<typeof PluginCreateFloorItems>
143
147
 
144
148
  /**
145
149
  * One door to place via {@linkcode PluginDesignCreateApi.doors} — the same
146
- * fields as a `"door"` {@linkcode PluginDesignCreateOpeningOptions}, so the
147
- * size overrides singular {@linkcode PluginDesignCreateApi.door} lacks are
148
- * available per item. `facing` and `hinge` are WORLD POINTS, not directions:
149
- * `facing` on the side of the wall the door swings open to, `hinge` near the
150
- * jamb it is hinged on. Rejects unknown fields.
150
+ * fields as a `"door"` {@linkcode PluginDesignCreateOpeningOptions}.
151
+ * Values are evaluated before cutting. Numeric lengths use SU; unit strings
152
+ * are accepted in values. `facing` selects local +Z; `hinge` sets the declared
153
+ * hand enum (left = local -X, right = +X). Both are world points.
151
154
  *
152
155
  * | Property | Type | Description |
153
156
  * |---|---|---|
154
- * | `catalogId` | `string` | Library id: team `_id` or general `fullName` |
157
+ * | `familyId` | `string` | Hosted door family definition ID |
158
+ * | `version` | `number`? | Exact version; newest known by default |
159
+ * | `values` | `Record<string, number \| string>`? | Authored parameter overrides |
155
160
  * | `hostWall` | {@linkcode ComponentHandle} | The wall to host the door |
156
161
  * | `position` | {@linkcode Vec3Handle} | World point projected onto the wall |
157
162
  * | `facing` | {@linkcode Vec3Handle}? | World point on the side the door swings open to (default engine-chosen) |
158
- * | `hinge` | {@linkcode Vec3Handle}? | World point near the jamb the door is hinged on (default the catalog item's authored side) |
163
+ * | `hinge` | {@linkcode Vec3Handle}? | World point near the hinged jamb; requires hand control |
159
164
  * | `label` | `string`? | Instance name (optional) |
160
- * | `width` | `number`? | Width override (Snaptrude units, > 0; default the catalog item's) |
161
- * | `height` | `number`? | Height override (Snaptrude units, > 0; default the catalog item's) |
165
+ * | `width` | `number`? | Declared width parameter (SU, > 0), not evaluated hole width |
166
+ * | `height` | `number`? | Declared height parameter (SU, > 0) |
162
167
  */
163
168
  export const PluginCreateDoorItem = z
164
169
  .object({ ...PluginOpeningBaseOptions })
@@ -183,15 +188,17 @@ export type PluginCreateDoorItems = z.infer<typeof PluginCreateDoorItems>
183
188
  *
184
189
  * | Property | Type | Description |
185
190
  * |---|---|---|
186
- * | `catalogId` | `string` | Library id: team `_id` or general `fullName` |
191
+ * | `familyId` | `string` | Hosted window family definition ID |
192
+ * | `version` | `number`? | Exact version; newest known by default |
193
+ * | `values` | `Record<string, number \| string>`? | Authored parameter overrides; numeric lengths use SU |
187
194
  * | `hostWall` | {@linkcode ComponentHandle} | The wall to host the window |
188
195
  * | `position` | {@linkcode Vec3Handle} | World point projected onto the wall |
189
196
  * | `facing` | {@linkcode Vec3Handle}? | World point on the side the window opens to (default engine-chosen) |
190
- * | `hinge` | {@linkcode Vec3Handle}? | World point near the jamb the window is hinged on (default the catalog item's authored side) |
197
+ * | `hinge` | {@linkcode Vec3Handle}? | World point near the hinged jamb; requires hand control |
191
198
  * | `label` | `string`? | Instance name (optional) |
192
- * | `width` | `number`? | Width override (Snaptrude units, > 0; default the catalog item's) |
193
- * | `height` | `number`? | Height override (Snaptrude units, > 0; default the catalog item's) |
194
- * | `sillHeight` | `number`? | Wall base to window bottom (Snaptrude units, ≥ 0; default the catalog item's) |
199
+ * | `width` | `number`? | Declared width parameter (SU, > 0), not evaluated hole width |
200
+ * | `height` | `number`? | Declared height parameter (SU, > 0) |
201
+ * | `sillHeight` | `number`? | Declared sill parameter (SU, ≥ 0); position Y is ignored |
195
202
  */
196
203
  export const PluginCreateWindowItem = z
197
204
  .object({
@@ -4,6 +4,7 @@ import {
4
4
  BrepHandle,
5
5
  ComponentHandle,
6
6
  ContourHandle,
7
+ LineHandle,
7
8
  CurveHandle,
8
9
  ProfileHandle,
9
10
  Vec3Handle,
@@ -29,6 +30,14 @@ import type {
29
30
  PluginCreateWindowItem,
30
31
  } from "./bulk-items"
31
32
  import { PluginWallTopProfile } from "./bulk-items"
33
+ import { PluginWallType } from "../types"
34
+ import {
35
+ PluginFamilyPlacement,
36
+ PluginFamilyFloorOptions,
37
+ PluginFamilySlabOptions,
38
+ PluginFamilyCeilingOptions,
39
+ PluginFamilyValues,
40
+ } from "../catalog"
32
41
 
33
42
  /**
34
43
  * `design.create.*` — author new scene-committed BIM entities.
@@ -43,7 +52,13 @@ import { PluginWallTopProfile } from "./bulk-items"
43
52
  * Footprint objects take a {@linkcode ContourHandle} (outer profile + holes);
44
53
  * build one with `snaptrude.core.geom.create.contourFromProfile(s)`.
45
54
  *
46
- * `door`/`window` place a catalog item into a host wall (the world point is
55
+ * Family overloads take `{ type, values? }` from `design.catalog`. The family supplies
56
+ * construction; the contour or axis supplies instance geometry. Geometry uses SU,
57
+ * while family length overrides use mm and angles use degrees. Omitted parameters
58
+ * retain family defaults; shared/type, formula and geometry-bound overrides are refused.
59
+ * Placement never publishes a definition. Unsupported references or geometry fail before mutation.
60
+ *
61
+ * `door`/`window` place a parametric family into a host wall (the world point is
47
62
  * projected onto the wall face to locate the opening; the wall is re-cut in one
48
63
  * undo entry) and throw if the point projects outside the wall. `smartLayout` is
49
64
  * the one creator returning a grouped {@linkcode PluginSmartLayoutResult} rather
@@ -219,20 +234,29 @@ export abstract class PluginDesignCreateApi {
219
234
  * ```
220
235
  */
221
236
  public abstract slab(
222
- contour: ContourHandle,
223
- thickness: number,
224
- direction?: "up" | "down",
225
- slabType?: PluginSlabType,
237
+ ...args:
238
+ | [
239
+ contour: ContourHandle,
240
+ thickness: number,
241
+ direction?: "up" | "down",
242
+ slabType?: PluginSlabType,
243
+ ]
244
+ | [contour: ContourHandle, options: PluginFamilySlabOptions]
226
245
  ): PluginApiReturn<ComponentHandle>
227
246
 
228
247
  /**
229
248
  * Create a **floor** by extruding a footprint contour by `thickness`
230
249
  * (extruded upward).
231
250
  *
251
+ * The native family overload takes `{ type, values?, position? }`. Contour
252
+ * geometry uses SU; family values use mm. The family supplies layer thickness.
253
+ * PG2 can split or merge the footprint, so both overloads return an array.
254
+ * A merge into an existing floor can return no newly created handles.
255
+ *
232
256
  * @param contour - Footprint (outer + holes)
233
257
  * @param thickness - Floor thickness (> 0)
234
258
  * @param position - Offset from origin
235
- * @returns the {@linkcode ComponentHandle} of the created floor
259
+ * @returns Newly created {@linkcode ComponentHandle}s; an empty array after a merge
236
260
  * @throws if the contour is invalid or the thickness is not positive
237
261
  *
238
262
  * @examplePrompt Create a floor from this room outline
@@ -247,15 +271,15 @@ export abstract class PluginDesignCreateApi {
247
271
  * const floor = await snaptrude.design.create.floor(contour, 0.1)
248
272
  * ```
249
273
  *
250
- * @performance For MORE THAN ONE floor, call `design.create.floors(items[])` — one
251
- * host round-trip and ONE undo entry for the whole batch. Looping this single-floor
252
- * creator is N round-trips and N undo entries.
274
+ * @performance For dimensional floors, `design.create.floors(items[])` uses one
275
+ * host round-trip and one undo entry. That bulk method does not accept native
276
+ * family options; use this method for a family-backed floor.
253
277
  */
254
278
  public abstract floor(
255
- contour: ContourHandle,
256
- thickness: number,
257
- position?: Vec3Handle,
258
- ): PluginApiReturn<ComponentHandle>
279
+ ...args:
280
+ | [contour: ContourHandle, thickness: number, position?: Vec3Handle]
281
+ | [contour: ContourHandle, options: PluginFamilyFloorOptions]
282
+ ): PluginApiReturn<ComponentHandle[]>
259
283
 
260
284
  /**
261
285
  * Create **many floors** in one undoable operation (bulk plural of
@@ -320,7 +344,7 @@ export abstract class PluginDesignCreateApi {
320
344
  */
321
345
  public abstract roof(
322
346
  contour: ContourHandle,
323
- thickness: number,
347
+ thickness: number | PluginFamilyPlacement,
324
348
  ): PluginApiReturn<ComponentHandle>
325
349
 
326
350
  /**
@@ -346,9 +370,9 @@ export abstract class PluginDesignCreateApi {
346
370
  * ```
347
371
  */
348
372
  public abstract ceiling(
349
- contour: ContourHandle,
350
- thickness: number,
351
- heightFromFloor?: number,
373
+ ...args:
374
+ | [contour: ContourHandle, thickness: number, heightFromFloor?: number]
375
+ | [contour: ContourHandle, options: PluginFamilyCeilingOptions]
352
376
  ): PluginApiReturn<ComponentHandle>
353
377
 
354
378
  /**
@@ -379,10 +403,14 @@ export abstract class PluginDesignCreateApi {
379
403
  * ```
380
404
  */
381
405
  public abstract column(
382
- position: Vec3Handle,
383
- crossSection: ContourHandle,
384
- height: number,
385
- directionUp?: Vec3Handle,
406
+ ...args:
407
+ | [
408
+ position: Vec3Handle,
409
+ crossSection: ContourHandle,
410
+ height: number,
411
+ directionUp?: Vec3Handle,
412
+ ]
413
+ | [axis: LineHandle, options: PluginFamilyPlacement]
386
414
  ): PluginApiReturn<ComponentHandle>
387
415
 
388
416
  /**
@@ -426,9 +454,9 @@ export abstract class PluginDesignCreateApi {
426
454
  * ```
427
455
  */
428
456
  public abstract beam(
429
- section: ContourHandle,
430
- length: number,
431
- direction?: Vec3Handle,
457
+ ...args:
458
+ | [section: ContourHandle, length: number, direction?: Vec3Handle]
459
+ | [axis: LineHandle, options: PluginFamilyPlacement]
432
460
  ): PluginApiReturn<ComponentHandle>
433
461
 
434
462
  /**
@@ -439,12 +467,12 @@ export abstract class PluginDesignCreateApi {
439
467
  * @param height - Wall height (default engine default)
440
468
  * @param thickness - Wall thickness (default: the `wallType`'s total layer
441
469
  * thickness when `wallType` is given, else the engine default)
442
- * @param wallType - Wall type to build with — the same searchable list the
443
- * Draw tab's Wall Type dropdown offers. Pass a name from
444
- * `design.types.list("wall")` (the summary's `label`, or its `"wall:…"` id).
445
- * Drives the wall's construction layers and default material, and — when
446
- * `thickness` is omitted — its total layer thickness. Default: the engine's
447
- * generic wall.
470
+ * @param wallType - Legacy label/`wall:` id, or the exact `nativeFamily`
471
+ * `{ id, version }` pin from `design.types.list("wall")`. Native pins are
472
+ * authorized on every use; selecting a family in Draw is not registration.
473
+ * Native pins support straight horizontal centerlines and flat tops only.
474
+ * Omit thickness for native pins; a conflicting explicit thickness rejects.
475
+ * Default: the engine's generic wall.
448
476
  * @param storey - Target storey (integer: `1` ground, `2` first floor, `-1`
449
477
  * basement — same convention as `design.create.space`). The walls are
450
478
  * assigned to it and lifted to its base elevation, all inside the same
@@ -503,9 +531,10 @@ export abstract class PluginDesignCreateApi {
503
531
  profile: ProfileHandle,
504
532
  height?: number,
505
533
  thickness?: number,
506
- wallType?: string,
534
+ wallType?: PluginWallType,
507
535
  storey?: number,
508
536
  topProfiles?: (PluginWallTopProfile | null)[],
537
+ values?: PluginFamilyValues,
509
538
  ): PluginApiReturn<ComponentHandle[]>
510
539
 
511
540
  /**
@@ -895,30 +924,23 @@ export abstract class PluginDesignCreateApi {
895
924
  ): PluginApiReturn<ComponentHandle[]>
896
925
 
897
926
  /**
898
- * Place a **door** from the catalog into a host wall.
927
+ * Place a parametric **door** family into a host wall.
899
928
  *
900
- * Identified by a **catalog (library) id** — the team object's stable `_id`
901
- * or the general library's `fullName`. Discover ids with
929
+ * Identified by a saved **family definition id**. Discover ids with
902
930
  * {@linkcode PluginDesignDoorsApi.listCatalog}. The world `position` is
903
931
  * projected onto the host wall's face to locate the opening; the wall is
904
932
  * re-cut and the door hosted in a single undo entry. Placement is
905
- * asynchronous (the source mesh is fetched if not cached).
933
+ * asynchronous. Values and host bindings are evaluated before the first cut.
906
934
  *
907
- * @param catalogId - Library id: team `_id` or general `fullName`
935
+ * @param familyId - Hosted door definition ID; legacy mesh catalog IDs are not accepted
908
936
  * @param hostWall - The wall to host the door
909
937
  * @param position - World point projected onto the wall to locate the opening
910
- * @param options - Optional placement options: `label` — instance name;
911
- * `hinge` — world point near the jamb the door is hinged on (the door is
912
- * reflected along the wall so its hinged jamb is the one nearer this
913
- * point; default the catalog item's authored hinge side)
914
- * @param facing - World point on the side of the wall the door swings open
915
- * to (the room it opens into — where the plan symbol draws the swing arc).
916
- * Any point clearly on that side works (e.g. the room's center). Default:
917
- * the engine picks a side (nondeterministic when `position` sits on the
918
- * wall centerline).
938
+ * @param options - `version` pins the definition. `values` sets authored parameters
939
+ * (numeric lengths in SU, or unit strings). `label` names the instance.
940
+ * `hinge` selects the declared `hand` enum: local -X is left, +X is right.
941
+ * @param facing - World point selecting local +Z; omitted uses the picked face
919
942
  * @returns the {@linkcode ComponentHandle} of the placed door
920
- * @throws if the catalog id is unknown, the host is not a wall, the source
921
- * mesh fails to load, or the projected point falls **outside** the host wall
943
+ * @throws if the family/category/parameters are invalid, or placement or cutting fails
922
944
  *
923
945
  * @examplePrompt Add a door to this wall here
924
946
  * @examplePrompt Place a sliding door on the selected wall
@@ -961,26 +983,28 @@ export abstract class PluginDesignCreateApi {
961
983
  * that single call. Looping this single-door creator is N round-trips.
962
984
  */
963
985
  public abstract door(
964
- catalogId: string,
986
+ familyId: string,
965
987
  hostWall: ComponentHandle,
966
988
  position: Vec3Handle,
967
- options?: { label?: string; hinge?: Vec3Handle },
989
+ options?: {
990
+ label?: string
991
+ hinge?: Vec3Handle
992
+ version?: number
993
+ values?: Record<string, number | string>
994
+ },
968
995
  facing?: Vec3Handle,
969
996
  ): PluginApiReturn<ComponentHandle>
970
997
 
971
998
  /**
972
999
  * Place **many doors** into host walls in one undoable operation (bulk plural
973
- * of {@linkcode door}). Each item carries its own catalog id, host wall,
1000
+ * of {@linkcode door}). Each item carries its own family id, host wall,
974
1001
  * world position, and optional `facing`, `label`, `width` and `height` — the
975
1002
  * same fields as a `"door"` {@linkcode PluginDesignCreateOpeningOptions}.
976
1003
  * Validate-all-or-throw; one command.
977
1004
  *
978
- * As with the singular creator, placing an opening **re-cuts its host wall**:
979
- * the wall you passed as `hostWall` stops resolving once the call returns.
980
- * Several items MAY name the same original wall handle in one call — the host
981
- * chains the re-cuts internally — but after the call recover the surviving
982
- * wall with `design.query.getHost(opening)`, never by reusing the handle you
983
- * passed in.
1005
+ * The wall keeps its identity. Several items may use the same host.
1006
+ * Width and height set named recipe parameters, not mesh scale. The recipe's
1007
+ * evaluated hole can include frame allowances. A failed item rolls back the batch.
984
1008
  *
985
1009
  * @param items - One {@linkcode PluginCreateDoorItem} per door to place
986
1010
  * (≥1, ≤1000)
@@ -988,10 +1012,9 @@ export abstract class PluginDesignCreateApi {
988
1012
  * @throws `VALIDATION` if the items fail the schema (empty array, more than
989
1013
  * 1000 items, unknown fields, a non-positive `width`/`height`);
990
1014
  * `HANDLE_INVALID` if a `position`, `facing` or `hinge` handle is unknown
991
- * or released; `PRECONDITION_FAILED` if a catalog id is unknown, a `hostWall`
992
- * is not a wall / is locked / is not in the active proposal, the projected
993
- * point falls outside its host wall, or a door tool is active;
994
- * `OPERATION_FAILED` if a source mesh fails to load or placement fails
1015
+ * or released; `PRECONDITION_FAILED` if the family cannot be resolved or saved,
1016
+ * or a host is locked / is not in the active proposal;
1017
+ * `OPERATION_FAILED` if placement, containment, overlap checks or cutting fail
995
1018
  * (nothing is created — `details.itemIndex` is the failing item);
996
1019
  * `METHOD_NOT_PERMITTED` if the plugin may not write.
997
1020
  *
@@ -1002,7 +1025,7 @@ export abstract class PluginDesignCreateApi {
1002
1025
  * @examplePrompt Add all the doors for this floor plan together
1003
1026
  *
1004
1027
  * @performance Bulk creator — the whole batch is ONE host round-trip and ONE undo
1005
- * entry, and each distinct catalog source loads once. Always prefer this over
1028
+ * entry. Always prefer this over
1006
1029
  * calling `design.create.door` in a loop: build the full `items[]` array first
1007
1030
  * (all host walls and points up front), then make one call.
1008
1031
  *
@@ -1012,10 +1035,10 @@ export abstract class PluginDesignCreateApi {
1012
1035
  * const [wall] = await snaptrude.design.query.listWalls({ isSelected: true })
1013
1036
  * const [entry] = await snaptrude.design.doors.listCatalog()
1014
1037
  * const [front, side] = await snaptrude.design.create.doors([
1015
- * { catalogId: entry.id, hostWall: wall, position: await v.new(2, 0, 5), label: "D-01" },
1016
- * { catalogId: entry.id, hostWall: wall, position: await v.new(6, 0, 5), width: 1.2 },
1038
+ * { familyId: entry.id, hostWall: wall, position: await v.new(2, 0, 5), label: "D-01" },
1039
+ * { familyId: entry.id, hostWall: wall, position: await v.new(6, 0, 5), values: { width: "1200mm" } },
1017
1040
  * ])
1018
- * // `wall` was re-cut twice and no longer resolves — ask the opening for its host:
1041
+ * // The host still resolves after both cuts:
1019
1042
  * const currentWall = await snaptrude.design.query.getHost(front)
1020
1043
  * ```
1021
1044
  */
@@ -1024,29 +1047,21 @@ export abstract class PluginDesignCreateApi {
1024
1047
  ): PluginApiReturn<ComponentHandle[]>
1025
1048
 
1026
1049
  /**
1027
- * Place a **window** from the catalog into a host wall.
1050
+ * Place a parametric **window** family into a host wall.
1028
1051
  *
1029
- * Identified by a **catalog (library) id** — the team object's stable `_id`
1030
- * or the general library's `fullName`. Discover ids with
1052
+ * Identified by a saved **family definition id**. Discover ids with
1031
1053
  * {@linkcode PluginDesignWindowsApi.listCatalog}. The world `position` is
1032
1054
  * projected onto the host wall's face to locate the opening; the wall is
1033
1055
  * re-cut and the window hosted in a single undo entry. Placement is
1034
- * asynchronous (the source mesh is fetched if not cached).
1056
+ * asynchronous. The sill parameter determines elevation; position Y is ignored.
1035
1057
  *
1036
- * @param catalogId - Library id: team `_id` or general `fullName`
1058
+ * @param familyId - Hosted window definition ID; legacy mesh catalog IDs are not accepted
1037
1059
  * @param hostWall - The wall to host the window
1038
1060
  * @param position - World point projected onto the wall to locate the opening
1039
- * @param options - Optional placement options: `label` — instance name;
1040
- * `hinge` — world point near the jamb the window is hinged on (same rule
1041
- * as {@linkcode PluginDesignCreateApi.door}; default the catalog item's
1042
- * authored side)
1043
- * @param facing - World point on the side of the wall the window opens to
1044
- * (matters for asymmetric windows, e.g. casement swing) — same convention
1045
- * as {@linkcode PluginDesignCreateApi.door}. Default: the engine picks a
1046
- * side (nondeterministic when `position` sits on the centerline).
1061
+ * @param options - `version`, `values`, `label`, and parameter-driven `hinge`, as for door
1062
+ * @param facing - World point selecting local +Z; omitted uses the picked face
1047
1063
  * @returns the {@linkcode ComponentHandle} of the placed window
1048
- * @throws if the catalog id is unknown, the host is not a wall, the source
1049
- * mesh fails to load, or the projected point falls **outside** the host wall
1064
+ * @throws if the family/category/parameters are invalid, or placement or cutting fails
1050
1065
  *
1051
1066
  * @examplePrompt Add a window to this wall here
1052
1067
  * @examplePrompt Place a casement window on the selected wall
@@ -1072,28 +1087,29 @@ export abstract class PluginDesignCreateApi {
1072
1087
  * inside that single call. Looping this single-window creator is N round-trips.
1073
1088
  */
1074
1089
  public abstract window(
1075
- catalogId: string,
1090
+ familyId: string,
1076
1091
  hostWall: ComponentHandle,
1077
1092
  position: Vec3Handle,
1078
- options?: { label?: string; hinge?: Vec3Handle },
1093
+ options?: {
1094
+ label?: string
1095
+ hinge?: Vec3Handle
1096
+ version?: number
1097
+ values?: Record<string, number | string>
1098
+ },
1079
1099
  facing?: Vec3Handle,
1080
1100
  ): PluginApiReturn<ComponentHandle>
1081
1101
 
1082
1102
  /**
1083
1103
  * Place **many windows** into host walls in one undoable operation (bulk
1084
- * plural of {@linkcode window}). Each item carries its own catalog id, host
1104
+ * plural of {@linkcode window}). Each item carries its own family id, host
1085
1105
  * wall, world position, and optional `facing`, `label`, `width`, `height` and
1086
1106
  * `sillHeight` — the same fields as a `"window"`
1087
1107
  * {@linkcode PluginDesignCreateOpeningOptions}. `sillHeight` is measured from
1088
1108
  * the host wall base to the BOTTOM of the window. Validate-all-or-throw; one
1089
1109
  * command.
1090
1110
  *
1091
- * As with the singular creator, placing an opening **re-cuts its host wall**:
1092
- * the wall you passed as `hostWall` stops resolving once the call returns.
1093
- * Several items MAY name the same original wall handle in one call — the host
1094
- * chains the re-cuts internally — but after the call recover the surviving
1095
- * wall with `design.query.getHost(opening)`, never by reusing the handle you
1096
- * passed in.
1111
+ * Hosts keep their identity. Width, height and sillHeight set the declared
1112
+ * width, height and sill parameters before the first cut. No mesh scaling occurs.
1097
1113
  *
1098
1114
  * @param items - One {@linkcode PluginCreateWindowItem} per window to place
1099
1115
  * (≥1, ≤1000)
@@ -1101,10 +1117,9 @@ export abstract class PluginDesignCreateApi {
1101
1117
  * @throws `VALIDATION` if the items fail the schema (empty array, more than
1102
1118
  * 1000 items, unknown fields, a non-positive `width`/`height`, a negative
1103
1119
  * `sillHeight`); `HANDLE_INVALID` if a `position`, `facing` or `hinge`
1104
- * handle is unknown or released; `PRECONDITION_FAILED` if a catalog id is unknown, a
1105
- * `hostWall` is not a wall / is locked / is not in the active proposal, the
1106
- * projected point falls outside its host wall, or a window tool is active;
1107
- * `OPERATION_FAILED` if a source mesh fails to load or placement fails
1120
+ * handle is unknown or released; `PRECONDITION_FAILED` if the family cannot be
1121
+ * resolved or saved, or a host is locked / is not in the active proposal;
1122
+ * `OPERATION_FAILED` if placement, containment, overlap checks or cutting fail
1108
1123
  * (nothing is created — `details.itemIndex` is the failing item);
1109
1124
  * `METHOD_NOT_PERMITTED` if the plugin may not write.
1110
1125
  *
@@ -1115,7 +1130,7 @@ export abstract class PluginDesignCreateApi {
1115
1130
  * @examplePrompt Add all the windows with a 0.9m sill height together
1116
1131
  *
1117
1132
  * @performance Bulk creator — the whole batch is ONE host round-trip and ONE undo
1118
- * entry, and each distinct catalog source loads once. Always prefer this over
1133
+ * entry. Always prefer this over
1119
1134
  * calling `design.create.window` in a loop: build the full `items[]` array first
1120
1135
  * (all host walls and points up front), then make one call.
1121
1136
  *
@@ -1125,8 +1140,8 @@ export abstract class PluginDesignCreateApi {
1125
1140
  * const [wall] = await snaptrude.design.query.listWalls({ isSelected: true })
1126
1141
  * const [casement] = await snaptrude.design.windows.listCatalog()
1127
1142
  * const placed = await snaptrude.design.create.windows([
1128
- * { catalogId: casement.id, hostWall: wall, position: await v.new(2, 0, 5), sillHeight: 0.9 },
1129
- * { catalogId: casement.id, hostWall: wall, position: await v.new(5, 0, 5), sillHeight: 0.9 },
1143
+ * { familyId: casement.id, hostWall: wall, position: await v.new(2, 0, 5), values: { sill: "900mm" } },
1144
+ * { familyId: casement.id, hostWall: wall, position: await v.new(5, 0, 5), values: { sill: "900mm" } },
1130
1145
  * ])
1131
1146
  * const currentWall = await snaptrude.design.query.getHost(placed[0])
1132
1147
  * ```
@@ -1136,17 +1151,17 @@ export abstract class PluginDesignCreateApi {
1136
1151
  ): PluginApiReturn<ComponentHandle[]>
1137
1152
 
1138
1153
  /**
1139
- * Place a catalog **door or window** into a host wall with optional size overrides.
1154
+ * Place a parametric **door or window** into a host wall with parameter overrides.
1140
1155
  *
1141
1156
  * The world `position` is projected onto the host wall to locate the opening.
1142
1157
  * All supplied dimensions use Snaptrude engine units. Window `sillHeight` is
1143
1158
  * measured from the host wall base to the bottom of the window, not to
1144
1159
  * its center. Placement is asynchronous and committed as one undoable creation.
1145
1160
  *
1146
- * @param options - Opening kind, catalog and host references, placement, and
1161
+ * @param options - Opening kind, family and host references, placement, and
1147
1162
  * optional facing (swing side), hinge (hinged jamb), label, and dimensions
1148
1163
  * @returns the {@linkcode ComponentHandle} of the placed door or window
1149
- * @throws if the options are invalid, the catalog id is unknown, the host is
1164
+ * @throws if the options are invalid, the family id is unknown, the host is
1150
1165
  * not a wall, loading fails, or the opening cannot be placed on the host
1151
1166
  *
1152
1167
  * @examplePrompt Add a 1m wide door to this wall here
@@ -1160,7 +1175,7 @@ export abstract class PluginDesignCreateApi {
1160
1175
  * ```ts
1161
1176
  * const opening = await snaptrude.design.create.opening({
1162
1177
  * kind: "window",
1163
- * catalogId: windowType.id,
1178
+ * familyId: windowType.id,
1164
1179
  * hostWall: wall,
1165
1180
  * position: await snaptrude.core.math.vec3.new(3, 0, 5),
1166
1181
  * width: 1.2,
@@ -1660,7 +1675,7 @@ export type PluginDesignCreateBeamArgs = z.infer<
1660
1675
  * | `profile` | {@linkcode ProfileHandle} | Ordered curve chain (wall centerlines) |
1661
1676
  * | `height` | `number`? | Wall height (default engine default) |
1662
1677
  * | `thickness` | `number`? | Wall thickness (default: `wallType`'s total layer thickness when given, else engine default) |
1663
- * | `wallType` | `string`? | Wall type name from `design.types.list("wall")` — layers/material/thickness defaults (default generic) |
1678
+ * | `wallType` | {@linkcode PluginWallType}? | Legacy name/id or exact native `{ id, version }` pin from `design.types.list("wall")` (default generic) |
1664
1679
  * | `storey` | `number`? | Target storey (integer, must exist) — walls assigned + lifted to its base in the same undo entry (default: geometry-derived) |
1665
1680
  * | `topProfiles` | ({@linkcode PluginWallTopProfile} \| `null`)[]? | Top edge per curve (same order); `null`/missing = flat at `height`. Straight curves only |
1666
1681
  */
@@ -1668,9 +1683,10 @@ export const PluginDesignCreateWallsArgs = z.object({
1668
1683
  profile: ProfileHandle,
1669
1684
  height: z.number().optional(),
1670
1685
  thickness: z.number().optional(),
1671
- wallType: z.string().min(1).optional(),
1686
+ wallType: PluginWallType.optional(),
1672
1687
  storey: z.number().int().optional(),
1673
1688
  topProfiles: z.array(PluginWallTopProfile.nullable()).optional(),
1689
+ values: PluginFamilyValues.optional(),
1674
1690
  })
1675
1691
  export type PluginDesignCreateWallsArgs = z.infer<
1676
1692
  typeof PluginDesignCreateWallsArgs
@@ -1743,26 +1759,23 @@ export type PluginDesignCreateFurnitureArgs = z.infer<
1743
1759
  *
1744
1760
  * | Property | Type | Description |
1745
1761
  * |---|---|---|
1746
- * | `catalogId` | `string` | Library id: team `_id` or general `fullName` |
1762
+ * | `familyId` | `string` | Hosted door family definition ID |
1763
+ * | `version` | `number`? | Exact version; newest known by default |
1764
+ * | `values` | `Record<string, number \| string>`? | Parameters; numeric lengths use SU |
1747
1765
  * | `hostWall` | {@linkcode ComponentHandle} | The wall to host the door |
1748
1766
  * | `position` | {@linkcode Vec3Handle} | World point projected onto the wall |
1749
1767
  * | `label` | `string`? | Instance name (optional) |
1750
1768
  * | `facing` | {@linkcode Vec3Handle}? | World point on the side of the wall the door swings open to (default engine-chosen) |
1751
- * | `hinge` | {@linkcode Vec3Handle}? | World point near the jamb the door is hinged on (default the catalog item's authored side) |
1769
+ * | `hinge` | {@linkcode Vec3Handle}? | World point near the hinged jamb; requires hand control |
1752
1770
  */
1753
1771
  export const PluginDesignCreateDoorArgs = z.object({
1754
- catalogId: z.string().min(1),
1755
- hostWall: ComponentHandle,
1756
- position: Vec3Handle,
1757
- label: z.string().optional(),
1758
- facing: Vec3Handle.optional(),
1759
- hinge: Vec3Handle.optional(),
1772
+ ...PluginOpeningBaseOptions,
1760
1773
  })
1761
1774
  export type PluginDesignCreateDoorArgs = z.infer<
1762
1775
  typeof PluginDesignCreateDoorArgs
1763
1776
  >
1764
1777
  // TRANSPORT: positional signature shipped — facing is the trailing 5th arg, hinge rides in options:
1765
- // door(catalogId: string, hostWall: ComponentHandle, position: Vec3Handle, options?: { label?, hinge? }, facing?: Vec3Handle)
1778
+ // door(familyId, hostWall, position, options?: { label?, hinge?, version?, values? }, facing?)
1766
1779
 
1767
1780
  // ---------------------------------------------------------------------------
1768
1781
  // window
@@ -1773,26 +1786,23 @@ export type PluginDesignCreateDoorArgs = z.infer<
1773
1786
  *
1774
1787
  * | Property | Type | Description |
1775
1788
  * |---|---|---|
1776
- * | `catalogId` | `string` | Library id: team `_id` or general `fullName` |
1789
+ * | `familyId` | `string` | Hosted window family definition ID |
1790
+ * | `version` | `number`? | Exact version; newest known by default |
1791
+ * | `values` | `Record<string, number \| string>`? | Parameters; numeric lengths use SU |
1777
1792
  * | `hostWall` | {@linkcode ComponentHandle} | The wall to host the window |
1778
1793
  * | `position` | {@linkcode Vec3Handle} | World point projected onto the wall |
1779
1794
  * | `label` | `string`? | Instance name (optional) |
1780
1795
  * | `facing` | {@linkcode Vec3Handle}? | World point on the side of the wall the window opens to (default engine-chosen) |
1781
- * | `hinge` | {@linkcode Vec3Handle}? | World point near the jamb the window is hinged on (default the catalog item's authored side) |
1796
+ * | `hinge` | {@linkcode Vec3Handle}? | World point near the hinged jamb; requires hand control |
1782
1797
  */
1783
1798
  export const PluginDesignCreateWindowArgs = z.object({
1784
- catalogId: z.string().min(1),
1785
- hostWall: ComponentHandle,
1786
- position: Vec3Handle,
1787
- label: z.string().optional(),
1788
- facing: Vec3Handle.optional(),
1789
- hinge: Vec3Handle.optional(),
1799
+ ...PluginOpeningBaseOptions,
1790
1800
  })
1791
1801
  export type PluginDesignCreateWindowArgs = z.infer<
1792
1802
  typeof PluginDesignCreateWindowArgs
1793
1803
  >
1794
1804
  // TRANSPORT: positional signature shipped — facing is the trailing 5th arg, hinge rides in options:
1795
- // window(catalogId: string, hostWall: ComponentHandle, position: Vec3Handle, options?: { label?, hinge? }, facing?: Vec3Handle)
1805
+ // window(familyId, hostWall, position, options?: { label?, hinge?, version?, values? }, facing?)
1796
1806
 
1797
1807
  // ---------------------------------------------------------------------------
1798
1808
  // opening