@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
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@snaptrude/plugin-core",
3
- "version": "0.9.15",
3
+ "version": "0.9.16-networks-20261009.1",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "module": "./dist/index.js",
@@ -115,6 +115,11 @@ export function buildManifest({ includeOptional = false } = {}) {
115
115
  const cls = classes.get(className)
116
116
  if (!cls) return
117
117
 
118
+ // Domain network namespaces inherit their transport methods. Include these
119
+ // leaves so discovery exposes the same API as the generic worker proxy.
120
+ const base = cls.getExtends()?.getExpression().getText()
121
+ if (base && classes.has(base)) walk(base, pathPrefix)
122
+
118
123
  // Leaf methods on this namespace.
119
124
  for (const method of cls.getMethods()) {
120
125
  const name = method.getName()
@@ -1,6 +1,6 @@
1
1
  import * as z from "zod"
2
2
  import { PluginApiReturn } from "../../../types"
3
- import { Vec3Handle } from "../../../handles"
3
+ import { Vec3Components, Vec3Handle } from "../../../handles"
4
4
 
5
5
  /**
6
6
  * Camera controls.
@@ -10,6 +10,13 @@ import { Vec3Handle } from "../../../handles"
10
10
  * canvas view menu and the 2D/3D toggle. Like {@linkcode PluginZoomApi}, these
11
11
  * are transient VIEW-STATE changes: they are not model edits, so they are not
12
12
  * write-gated and are not undoable. Accessed via `snaptrude.core.camera`.
13
+ *
14
+ * Read and set the full camera pose (`getPose`/`setPose`), walk and turn it the
15
+ * way the arrow keys do (`move`/`rotate`), and read or change the arrow-key
16
+ * navigation settings (`getNavigationSettings`/`updateNavigationSettings`).
17
+ * Positions are world coordinates in internal `babylon` units (1 unit =
18
+ * 0.254 m, Y up); yaw is degrees clockwise from +z seen from above, pitch is
19
+ * degrees above level.
13
20
  */
14
21
  export abstract class PluginCameraApi {
15
22
  constructor() {}
@@ -184,6 +191,180 @@ export abstract class PluginCameraApi {
184
191
  * ```
185
192
  */
186
193
  public abstract zoomSelection(): PluginApiReturn<boolean>
194
+
195
+ /**
196
+ * Read where the camera is and where it looks: the eye and target positions
197
+ * (world coordinates, internal `babylon` units), the view direction as yaw
198
+ * and pitch, the vertical field of view, the projection and the 2D/3D mode.
199
+ * Paired with {@linkcode PluginCameraApi.setPose}.
200
+ *
201
+ * @returns The current {@linkcode PluginCameraPose}.
202
+ * @throws PRECONDITION_FAILED when there is no active camera.
203
+ *
204
+ * @examplePrompt Where is the camera right now?
205
+ * @examplePrompt Remember this viewpoint so we can come back to it
206
+ * @examplePrompt Which way is the camera facing?
207
+ * @examplePrompt How high above the ground is the camera?
208
+ *
209
+ * # Example
210
+ * ```ts
211
+ * const pose = await snaptrude.core.camera.getPose()
212
+ * console.log(pose.eye, pose.yawInDegrees, pose.pitchInDegrees)
213
+ * ```
214
+ */
215
+ public abstract getPose(): PluginApiReturn<PluginCameraPose>
216
+
217
+ /**
218
+ * Place the camera, optionally easing there over `options.durationInSeconds`,
219
+ * and resolve once the new view has been drawn, so a capture that follows sees
220
+ * it without a fixed wait. `pose` is one of:
221
+ *
222
+ * - `{ eye, target }`: stand at `eye` looking at `target`, as
223
+ * {@linkcode PluginCameraApi.lookFrom} does with handles;
224
+ * - `{ eye, yawInDegrees, pitchInDegrees }`: stand at `eye` looking along a
225
+ * direction;
226
+ * - `{ standAt, yawInDegrees? }`: stand on the floor, stair, terrain or
227
+ * ground at or below `standAt`, at the user's eye height above it (the `I`
228
+ * key), facing `yawInDegrees` (the current yaw when omitted).
229
+ *
230
+ * Stops a playing walkthrough and switches from 2D plan view to 3D first.
231
+ * View-state only: not write-gated, not undoable.
232
+ *
233
+ * @param pose - Where to put the camera ({@linkcode PluginCameraPoseInput})
234
+ * @param options - `durationInSeconds`: ease over this long (0 to 10, default 0 jumps)
235
+ * @returns The camera's {@linkcode PluginCameraPose} once it has arrived.
236
+ * @throws PRECONDITION_FAILED when there is no active camera, while a
237
+ * walkthrough export is recording, or when `standAt` lies below the ground
238
+ * with nothing under it. VALIDATION when `eye` and `target` coincide or a
239
+ * pitch is beyond ±89°.
240
+ *
241
+ * @examplePrompt Stand in the living room at eye level facing the window
242
+ * @examplePrompt Move the camera to (40, 12, 30) looking at the entrance
243
+ * @examplePrompt Fly the camera smoothly over to the courtyard
244
+ * @examplePrompt Put me back at the viewpoint we saved earlier
245
+ *
246
+ * # Example
247
+ * ```ts
248
+ * const { camera } = snaptrude.core
249
+ * await camera.setPose({ standAt: { x: 20, y: 0, z: 35 }, yawInDegrees: 90 })
250
+ * await camera.setPose(
251
+ * { eye: { x: 60, y: 25, z: 60 }, target: { x: 0, y: 5, z: 0 } },
252
+ * { durationInSeconds: 1.5 },
253
+ * )
254
+ * ```
255
+ */
256
+ public abstract setPose(
257
+ pose: PluginCameraPoseInput,
258
+ options?: PluginCameraSetPoseOptions,
259
+ ): PluginApiReturn<PluginCameraPose>
260
+
261
+ /**
262
+ * Walk or fly the camera by a displacement in its own frame: `forward` along
263
+ * the level view direction, `right` to its side and `up` vertically, in
264
+ * internal `babylon` units. The view direction does not change. With
265
+ * `options.followsFloor` the camera keeps its height above the floor as it
266
+ * goes, climbing and descending stairs and ramps the way the arrow keys do.
267
+ * Stops a playing walkthrough and switches from 2D plan view to 3D first.
268
+ * View-state only: not write-gated, not undoable.
269
+ *
270
+ * @param displacement - {@linkcode PluginCameraMoveDisplacement}; omitted components are 0
271
+ * @param options - `followsFloor` (default `false`) and `durationInSeconds` (0 to 10, default 0)
272
+ * @returns The camera's {@linkcode PluginCameraPose} after the move.
273
+ * @throws PRECONDITION_FAILED when there is no active camera, or while a
274
+ * walkthrough export is recording.
275
+ *
276
+ * @examplePrompt Walk forward 3 metres
277
+ * @examplePrompt Step to the right a little
278
+ * @examplePrompt Walk up the stairs ahead
279
+ * @examplePrompt Raise the camera by 2 metres
280
+ *
281
+ * # Example
282
+ * ```ts
283
+ * const metre = 1 / 0.254
284
+ * await snaptrude.core.camera.move(
285
+ * { forward: 3 * metre },
286
+ * { followsFloor: true, durationInSeconds: 2 },
287
+ * )
288
+ * ```
289
+ */
290
+ public abstract move(
291
+ displacement: PluginCameraMoveDisplacement,
292
+ options?: PluginCameraMoveOptions,
293
+ ): PluginApiReturn<PluginCameraPose>
294
+
295
+ /**
296
+ * Turn the camera in place by signed angles: `yawInDegrees` to the right
297
+ * (clockwise seen from above) and `pitchInDegrees` up. The eye does not move;
298
+ * the resulting pitch is kept within ±89°. Stops a playing walkthrough and
299
+ * switches from 2D plan view to 3D first. View-state only: not write-gated,
300
+ * not undoable.
301
+ *
302
+ * @param yawInDegrees - Turn to the right by this much (negative turns left)
303
+ * @param pitchInDegrees - Tilt up by this much (negative tilts down; default 0)
304
+ * @param options - `durationInSeconds` (0 to 10, default 0)
305
+ * @returns The camera's {@linkcode PluginCameraPose} after turning.
306
+ * @throws PRECONDITION_FAILED when there is no active camera, or while a
307
+ * walkthrough export is recording.
308
+ *
309
+ * @examplePrompt Turn around
310
+ * @examplePrompt Look 45 degrees to the left
311
+ * @examplePrompt Tilt the camera down a bit
312
+ *
313
+ * # Example
314
+ * ```ts
315
+ * await snaptrude.core.camera.rotate(180, 0, { durationInSeconds: 1 })
316
+ * ```
317
+ */
318
+ public abstract rotate(
319
+ yawInDegrees: number,
320
+ pitchInDegrees?: number,
321
+ options?: PluginCameraRotateOptions,
322
+ ): PluginApiReturn<PluginCameraPose>
323
+
324
+ /**
325
+ * Read the arrow-key navigation settings: whether the arrow keys walk the
326
+ * camera, the eye height used by `setPose`'s `standAt` and by walkthroughs
327
+ * that follow the floor, the walking speed, and whether walking stops at
328
+ * walls. Paired with {@linkcode PluginCameraApi.updateNavigationSettings}.
329
+ *
330
+ * @returns The current {@linkcode PluginCameraNavigationSettings}.
331
+ *
332
+ * @examplePrompt Is arrow-key navigation on?
333
+ * @examplePrompt What eye height does the camera use?
334
+ *
335
+ * # Example
336
+ * ```ts
337
+ * const { isKeyboardNavigationEnabled } =
338
+ * await snaptrude.core.camera.getNavigationSettings()
339
+ * ```
340
+ */
341
+ public abstract getNavigationSettings(): PluginApiReturn<PluginCameraNavigationSettings>
342
+
343
+ /**
344
+ * Change arrow-key navigation settings; only the fields given change.
345
+ * `isKeyboardNavigationEnabled` is the user's Project Settings switch and is
346
+ * saved on this device; the other settings last for the session.
347
+ * Write-gated: this changes the user's preferences, not just the view.
348
+ *
349
+ * @param patch - The settings to change ({@linkcode PluginCameraNavigationSettingsPatch})
350
+ * @returns The {@linkcode PluginCameraNavigationSettings} after the change.
351
+ * @throws METHOD_NOT_PERMITTED when plugin writes are disabled.
352
+ *
353
+ * @examplePrompt Turn off arrow-key navigation
354
+ * @examplePrompt Use a 1.6 m eye height
355
+ * @examplePrompt Make walking stop at walls
356
+ *
357
+ * # Example
358
+ * ```ts
359
+ * await snaptrude.core.camera.updateNavigationSettings({
360
+ * eyeHeight: 1.6 / 0.254,
361
+ * isCollisionEnabled: true,
362
+ * })
363
+ * ```
364
+ */
365
+ public abstract updateNavigationSettings(
366
+ patch: PluginCameraNavigationSettingsPatch,
367
+ ): PluginApiReturn<PluginCameraNavigationSettings>
187
368
  }
188
369
 
189
370
  /**
@@ -266,3 +447,221 @@ export const PluginCameraSetProjectionArgs = z.object({
266
447
  export type PluginCameraSetProjectionArgs = z.infer<
267
448
  typeof PluginCameraSetProjectionArgs
268
449
  >
450
+
451
+ // Plain {x, y, z} record with finite components (the brepFromRevolution `axisOrigin` pattern).
452
+ const FiniteVec3Components = z.object({
453
+ x: z.number().finite(),
454
+ y: z.number().finite(),
455
+ z: z.number().finite(),
456
+ })
457
+
458
+ /** Pitch is kept off the vertical, where yaw has no meaning. */
459
+ const PitchInDegrees = z.number().finite().min(-89).max(89)
460
+
461
+ /** How long a camera move eases for; 0 jumps. */
462
+ const DurationInSeconds = z.number().finite().min(0).max(10)
463
+
464
+ /**
465
+ * The camera's pose — result of {@linkcode PluginCameraApi.getPose},
466
+ * {@linkcode PluginCameraApi.setPose}, {@linkcode PluginCameraApi.move} and
467
+ * {@linkcode PluginCameraApi.rotate}.
468
+ *
469
+ * | Property | Type | Description |
470
+ * |---|---|---|
471
+ * | `eye` | `{ x, y, z }` | Camera position (world, `babylon` units) |
472
+ * | `target` | `{ x, y, z }` | Point the camera looks at |
473
+ * | `yawInDegrees` | `number` | View direction, degrees clockwise from +z seen from above (-180 to 180) |
474
+ * | `pitchInDegrees` | `number` | View direction, degrees above level (negative looks down) |
475
+ * | `fieldOfViewInDegrees` | `number` | Vertical field of view |
476
+ * | `projection` | {@linkcode PluginCameraProjection} | `"perspective"` or `"orthographic"` |
477
+ * | `mode` | {@linkcode PluginCameraMode} | `"2d"` or `"3d"` |
478
+ */
479
+ export const PluginCameraPose = z.object({
480
+ eye: Vec3Components,
481
+ target: Vec3Components,
482
+ yawInDegrees: z.number(),
483
+ pitchInDegrees: z.number(),
484
+ fieldOfViewInDegrees: z.number(),
485
+ projection: PluginCameraProjection,
486
+ mode: PluginCameraMode,
487
+ })
488
+ export type PluginCameraPose = z.infer<typeof PluginCameraPose>
489
+
490
+ /**
491
+ * Where {@linkcode PluginCameraApi.setPose} puts the camera — exactly one of:
492
+ *
493
+ * | Shape | Meaning |
494
+ * |---|---|
495
+ * | `{ eye, target }` | Stand at `eye` looking at `target` |
496
+ * | `{ eye, yawInDegrees, pitchInDegrees }` | Stand at `eye` looking along a direction (pitch within ±89°) |
497
+ * | `{ standAt, yawInDegrees? }` | Stand at eye height on the floor, stair, terrain or ground at or below `standAt`, facing `yawInDegrees` (default: current yaw) |
498
+ *
499
+ * Points are plain `{ x, y, z }` world coordinates in `babylon` units.
500
+ */
501
+ export const PluginCameraPoseInput = z.union([
502
+ z
503
+ .object({ eye: FiniteVec3Components, target: FiniteVec3Components })
504
+ .strict(),
505
+ z
506
+ .object({
507
+ eye: FiniteVec3Components,
508
+ yawInDegrees: z.number().finite(),
509
+ pitchInDegrees: PitchInDegrees,
510
+ })
511
+ .strict(),
512
+ z
513
+ .object({
514
+ standAt: FiniteVec3Components,
515
+ yawInDegrees: z.number().finite().optional(),
516
+ })
517
+ .strict(),
518
+ ])
519
+ export type PluginCameraPoseInput = z.infer<typeof PluginCameraPoseInput>
520
+
521
+ /**
522
+ * Options for {@linkcode PluginCameraApi.setPose}.
523
+ *
524
+ * | Property | Type | Description |
525
+ * |---|---|---|
526
+ * | `durationInSeconds` | `number \| undefined` | Ease to the pose over this long (0 to 10; default 0 jumps) |
527
+ */
528
+ export const PluginCameraSetPoseOptions = z
529
+ .object({ durationInSeconds: DurationInSeconds.optional() })
530
+ .strict()
531
+ export type PluginCameraSetPoseOptions = z.infer<
532
+ typeof PluginCameraSetPoseOptions
533
+ >
534
+
535
+ /**
536
+ * Arguments for {@linkcode PluginCameraApi.setPose}.
537
+ */
538
+ export const PluginCameraSetPoseArgs = z.object({
539
+ pose: PluginCameraPoseInput,
540
+ options: PluginCameraSetPoseOptions.optional(),
541
+ })
542
+ export type PluginCameraSetPoseArgs = z.infer<typeof PluginCameraSetPoseArgs>
543
+
544
+ /**
545
+ * A displacement in the camera's own frame, for {@linkcode PluginCameraApi.move}
546
+ * (`babylon` units; omitted components are 0).
547
+ *
548
+ * | Property | Type | Description |
549
+ * |---|---|---|
550
+ * | `forward` | `number \| undefined` | Along the level view direction (negative walks back) |
551
+ * | `right` | `number \| undefined` | To the camera's right (negative steps left) |
552
+ * | `up` | `number \| undefined` | Vertically (negative descends) |
553
+ */
554
+ export const PluginCameraMoveDisplacement = z
555
+ .object({
556
+ forward: z.number().finite().optional(),
557
+ right: z.number().finite().optional(),
558
+ up: z.number().finite().optional(),
559
+ })
560
+ .strict()
561
+ export type PluginCameraMoveDisplacement = z.infer<
562
+ typeof PluginCameraMoveDisplacement
563
+ >
564
+
565
+ /**
566
+ * Options for {@linkcode PluginCameraApi.move}.
567
+ *
568
+ * | Property | Type | Description |
569
+ * |---|---|---|
570
+ * | `followsFloor` | `boolean \| undefined` | Keep the height above the floor, climbing stairs and ramps (default `false`) |
571
+ * | `durationInSeconds` | `number \| undefined` | Walk over this long (0 to 10; default 0 jumps) |
572
+ */
573
+ export const PluginCameraMoveOptions = z
574
+ .object({
575
+ followsFloor: z.boolean().optional(),
576
+ durationInSeconds: DurationInSeconds.optional(),
577
+ })
578
+ .strict()
579
+ export type PluginCameraMoveOptions = z.infer<typeof PluginCameraMoveOptions>
580
+
581
+ /**
582
+ * Arguments for {@linkcode PluginCameraApi.move}.
583
+ */
584
+ export const PluginCameraMoveArgs = z.object({
585
+ displacement: PluginCameraMoveDisplacement,
586
+ options: PluginCameraMoveOptions.optional(),
587
+ })
588
+ export type PluginCameraMoveArgs = z.infer<typeof PluginCameraMoveArgs>
589
+
590
+ /**
591
+ * Options for {@linkcode PluginCameraApi.rotate}.
592
+ *
593
+ * | Property | Type | Description |
594
+ * |---|---|---|
595
+ * | `durationInSeconds` | `number \| undefined` | Turn over this long (0 to 10; default 0 jumps) |
596
+ */
597
+ export const PluginCameraRotateOptions = z
598
+ .object({ durationInSeconds: DurationInSeconds.optional() })
599
+ .strict()
600
+ export type PluginCameraRotateOptions = z.infer<
601
+ typeof PluginCameraRotateOptions
602
+ >
603
+
604
+ /**
605
+ * Arguments for {@linkcode PluginCameraApi.rotate}.
606
+ */
607
+ export const PluginCameraRotateArgs = z.object({
608
+ yawInDegrees: z.number().finite(),
609
+ pitchInDegrees: z.number().finite().optional(),
610
+ options: PluginCameraRotateOptions.optional(),
611
+ })
612
+ export type PluginCameraRotateArgs = z.infer<typeof PluginCameraRotateArgs>
613
+
614
+ /**
615
+ * How fast the arrow keys walk: the Slow / Normal / Fast navigation setting.
616
+ */
617
+ export const PluginCameraWalkSpeed = z.enum(["slow", "normal", "fast"])
618
+ export type PluginCameraWalkSpeed = z.infer<typeof PluginCameraWalkSpeed>
619
+
620
+ /**
621
+ * The arrow-key navigation settings — result of
622
+ * {@linkcode PluginCameraApi.getNavigationSettings} and
623
+ * {@linkcode PluginCameraApi.updateNavigationSettings}.
624
+ *
625
+ * | Property | Type | Description |
626
+ * |---|---|---|
627
+ * | `isKeyboardNavigationEnabled` | `boolean` | Whether the arrow keys walk the camera (Project Settings) |
628
+ * | `eyeHeight` | `number` | Eye height above the floor, `babylon` units |
629
+ * | `walkSpeed` | {@linkcode PluginCameraWalkSpeed} | Arrow-key walking speed |
630
+ * | `isCollisionEnabled` | `boolean` | Whether walking stops at walls |
631
+ */
632
+ export const PluginCameraNavigationSettings = z.object({
633
+ isKeyboardNavigationEnabled: z.boolean(),
634
+ eyeHeight: z.number(),
635
+ walkSpeed: PluginCameraWalkSpeed,
636
+ isCollisionEnabled: z.boolean(),
637
+ })
638
+ export type PluginCameraNavigationSettings = z.infer<
639
+ typeof PluginCameraNavigationSettings
640
+ >
641
+
642
+ /**
643
+ * The settings to change in {@linkcode PluginCameraApi.updateNavigationSettings};
644
+ * omitted fields keep their value. `eyeHeight` is in `babylon` units, between
645
+ * 0.8 m and 2.5 m (3.15 to 9.84 units).
646
+ */
647
+ export const PluginCameraNavigationSettingsPatch = z
648
+ .object({
649
+ isKeyboardNavigationEnabled: z.boolean().optional(),
650
+ eyeHeight: z.number().finite().min(3.15).max(9.84).optional(),
651
+ walkSpeed: PluginCameraWalkSpeed.optional(),
652
+ isCollisionEnabled: z.boolean().optional(),
653
+ })
654
+ .strict()
655
+ export type PluginCameraNavigationSettingsPatch = z.infer<
656
+ typeof PluginCameraNavigationSettingsPatch
657
+ >
658
+
659
+ /**
660
+ * Arguments for {@linkcode PluginCameraApi.updateNavigationSettings}.
661
+ */
662
+ export const PluginCameraUpdateNavigationSettingsArgs = z.object({
663
+ patch: PluginCameraNavigationSettingsPatch,
664
+ })
665
+ export type PluginCameraUpdateNavigationSettingsArgs = z.infer<
666
+ typeof PluginCameraUpdateNavigationSettingsArgs
667
+ >
@@ -0,0 +1,121 @@
1
+ import * as z from "zod"
2
+ import { ComponentHandle } from "../../handles"
3
+ import type { PluginApiReturn } from "../../types"
4
+ import { PluginConstructionType, PluginFamilyValues } from "./catalog"
5
+ import { PluginFamilyBundleSchema } from "./family"
6
+
7
+ const id = z.string().min(1).max(300)
8
+ const spaces = z.array(ComponentHandle).min(1).max(1000)
9
+
10
+ /** Read scope. Omit spaces to inspect the active proposal's sketch spaces. */
11
+ export const PluginBimContextArgs = z.object({ spaces: spaces.optional() }).strict()
12
+ export type PluginBimContextArgs = z.infer<typeof PluginBimContextArgs>
13
+
14
+ /** Directed graph edge. Side A lies along world-up × curve-direction; side B is opposite.
15
+ * Region IDs are snapshot identifiers, not component handles. Null means no adjacent region.
16
+ */
17
+ export const PluginBimEdge = z.object({
18
+ id,
19
+ startMm: z.tuple([z.number(), z.number(), z.number()]),
20
+ endMm: z.tuple([z.number(), z.number(), z.number()]),
21
+ lengthMm: z.number(),
22
+ heightMm: z.number(),
23
+ sideA: id.nullable(),
24
+ sideB: id.nullable(),
25
+ wall: ComponentHandle.nullable(),
26
+ supported: z.boolean(),
27
+ })
28
+ export type PluginBimEdge = z.infer<typeof PluginBimEdge>
29
+
30
+ /** Construction context is detached. Revision covers geometry, room metadata and construction state. */
31
+ export const PluginBimContext = z.object({
32
+ revision: id,
33
+ proposalId: id,
34
+ units: z.literal("mm"),
35
+ spaces: z.array(z.object({
36
+ component: ComponentHandle,
37
+ label: z.string(),
38
+ storey: z.number(),
39
+ eligible: z.boolean(),
40
+ reason: z.string().optional(),
41
+ })),
42
+ regions: z.array(z.object({ id, spaces: z.array(ComponentHandle) })),
43
+ edges: z.array(PluginBimEdge),
44
+ })
45
+ export type PluginBimContext = z.infer<typeof PluginBimContext>
46
+
47
+ /** Plan-local key selects either an existing construction or a new project-only native recipe.
48
+ * Bundles use the native DSL's SU/unit-expression rules; values overrides use mm/degrees.
49
+ */
50
+ export const PluginBimConstruction = z.union([
51
+ z.object({ key: id, reference: PluginConstructionType }).strict(),
52
+ z.object({ key: id, bundle: PluginFamilyBundleSchema }).strict(),
53
+ ])
54
+ export type PluginBimConstruction = z.infer<typeof PluginBimConstruction>
55
+
56
+ /** Every unwalled edge in the selected scope needs exactly one assignment.
57
+ * The first authored layer faces sideA unless reversed. Alignment sets the initial core-centre offset.
58
+ * Later parameter edits preserve the offset and reject invalid core alignment.
59
+ */
60
+ export const PluginBimWallAssignment = z.object({
61
+ edgeId: id,
62
+ construction: id,
63
+ values: PluginFamilyValues.optional(),
64
+ reversed: z.boolean(),
65
+ alignment: z.literal("coreCentre"),
66
+ }).strict()
67
+ export type PluginBimWallAssignment = z.infer<typeof PluginBimWallAssignment>
68
+
69
+ export const PluginBimPrepareArgs = z.object({
70
+ revision: id,
71
+ spaces,
72
+ constructions: z.array(PluginBimConstruction).max(1000),
73
+ walls: z.array(PluginBimWallAssignment).max(10000),
74
+ }).strict()
75
+ export type PluginBimPrepareArgs = z.infer<typeof PluginBimPrepareArgs>
76
+
77
+ /** Expected recipe/plan failures are diagnostics. No scene or library change occurs during prepare. */
78
+ export const PluginBimPreparation = z.object({
79
+ ok: z.boolean(),
80
+ preparationId: id.optional(),
81
+ diagnostics: z.array(z.object({ path: z.string(), message: z.string() })),
82
+ })
83
+ export type PluginBimPreparation = z.infer<typeof PluginBimPreparation>
84
+ export const PluginBimCreateArgs = z.object({ preparationId: id }).strict()
85
+
86
+ /** Source IDs identify removed sketch spaces, not live handles. Successful storeys share one undo step.
87
+ * Failed storeys remain spaces. Cancellation rolls back the whole conversion. Persistence is queued
88
+ * through normal model commands; this result is not a durable server-save acknowledgement.
89
+ */
90
+ export const PluginBimResult = z.object({
91
+ status: z.enum(["created", "partial", "cancelled", "unchanged"]),
92
+ convertedSpaceIds: z.array(z.string()),
93
+ created: z.array(ComponentHandle),
94
+ kept: z.array(z.object({ space: ComponentHandle, reason: z.string() })),
95
+ })
96
+ export type PluginBimResult = z.infer<typeof PluginBimResult>
97
+
98
+ /** Agent-driven Sketch-to-BIM. Uses PG2 topology; never redraws routes or publishes library families. */
99
+ export abstract class PluginDesignBimApi {
100
+ /** Read room adjacency and native conversion eligibility in the active proposal.
101
+ * @param options Optional explicit spaces; filters edges but keeps adjacent room metadata.
102
+ * @returns Rooms, directed boundaries in mm, eligibility and revision.
103
+ * @examplePrompt Inspect the rooms on each side of these sketch wall boundaries
104
+ */
105
+ abstract getContext(options?: PluginBimContextArgs): PluginApiReturn<PluginBimContext>
106
+
107
+ /** Stage a complete wall-construction assignment. A new prepare replaces this plugin's prior plan.
108
+ * @param plan Exact context revision, selected spaces, constructions and edge assignments.
109
+ * @returns Diagnostics or an opaque preparation ID, scoped to the caller and current project.
110
+ * @examplePrompt Validate wall layer assignments before converting sketch rooms to BIM
111
+ */
112
+ abstract prepare(plan: PluginBimPrepareArgs): PluginApiReturn<PluginBimPreparation>
113
+
114
+ /** Execute native Sketch-to-BIM. Revalidates scope, catalogue access and construction before mutation.
115
+ * Uses native progress/cancel controls and worker cancellation. Floors/roofs retain project defaults.
116
+ * @param preparationId ID returned by prepare. Consumed once; stale or foreign IDs throw PRECONDITION_FAILED.
117
+ * @returns Created component handles and explicit converted/kept outcomes, including partial success.
118
+ * @examplePrompt Convert these sketch rooms to BIM with wall layers chosen for each room boundary
119
+ */
120
+ abstract create(preparationId: string): PluginApiReturn<PluginBimResult>
121
+ }
@@ -0,0 +1,128 @@
1
+ import * as z from "zod"
2
+ import { ContourHandle, LineHandle, Vec3Handle } from "../../handles"
3
+ import type { PluginApiReturn } from "../../types"
4
+ import { PluginFamilyDefinitionParameter, PluginFamilyBundleSchema } from "./family"
5
+ import { NetworkFamilyContract } from "./networks"
6
+
7
+ /** Exact saved family identity. A label or a selected Draw type is not an identity. */
8
+ export const PluginSavedFamilyReference = z
9
+ .object({
10
+ id: z.string().min(1),
11
+ version: z.number().int().positive(),
12
+ })
13
+ .strict()
14
+ export type PluginSavedFamilyReference = z.infer<
15
+ typeof PluginSavedFamilyReference
16
+ >
17
+
18
+ /** Public overrides: physical lengths use mm, angles use degrees. Omitted values retain defaults. */
19
+ export const PluginFamilyValues = z.record(
20
+ z.string(),
21
+ z.union([z.number().finite(), z.string(), z.boolean()]),
22
+ )
23
+ export type PluginFamilyValues = z.infer<typeof PluginFamilyValues>
24
+
25
+ /** Native construction uses a saved family or a project assembly token from the catalogue. */
26
+ export const PluginConstructionType = z.union([
27
+ PluginSavedFamilyReference,
28
+ z.string().min(1),
29
+ ])
30
+ export type PluginConstructionType = z.infer<typeof PluginConstructionType>
31
+
32
+ /** Family owns its layers/section. Geometry owns the footprint/axis; it is never a values override. */
33
+ export const PluginFamilyPlacement = z
34
+ .object({
35
+ type: PluginConstructionType,
36
+ values: PluginFamilyValues.optional(),
37
+ })
38
+ .strict()
39
+ export type PluginFamilyPlacement = z.infer<typeof PluginFamilyPlacement>
40
+
41
+ /** Sparse native family edit. Omitted type keeps the component's exact saved reference. */
42
+ export const PluginFamilyUpdates = PluginFamilyPlacement.partial().refine(
43
+ (updates) => updates.type !== undefined || updates.values !== undefined,
44
+ { message: "Supply a type or parameter values" },
45
+ )
46
+ export type PluginFamilyUpdates = z.infer<typeof PluginFamilyUpdates>
47
+
48
+ export const PluginFamilyFloorOptions = PluginFamilyPlacement.extend({
49
+ position: Vec3Handle.optional(),
50
+ })
51
+ export type PluginFamilyFloorOptions = z.infer<typeof PluginFamilyFloorOptions>
52
+ export const PluginFamilySlabOptions = PluginFamilyPlacement.extend({
53
+ direction: z.enum(["up", "down"]).optional(),
54
+ })
55
+ export type PluginFamilySlabOptions = z.infer<typeof PluginFamilySlabOptions>
56
+ export const PluginFamilyCeilingOptions = PluginFamilyPlacement.extend({
57
+ heightFromFloor: z.number().finite().optional(),
58
+ })
59
+ export type PluginFamilyCeilingOptions = z.infer<
60
+ typeof PluginFamilyCeilingOptions
61
+ >
62
+ export const PluginFamilyContourArgs = z.object({
63
+ contour: ContourHandle,
64
+ options: PluginFamilyPlacement,
65
+ })
66
+ export const PluginFamilyAxisArgs = z.object({
67
+ axis: LineHandle,
68
+ options: PluginFamilyPlacement,
69
+ })
70
+
71
+ /** Inventory includes architectural recipes, ordinary PCs, and the existing placement libraries. */
72
+ export const PluginCatalogKind = z.enum([
73
+ "wall",
74
+ "floor",
75
+ "slab",
76
+ "roof",
77
+ "ceiling",
78
+ "beam",
79
+ "column",
80
+ "component",
81
+ "door",
82
+ "window",
83
+ "furniture",
84
+ ])
85
+ export type PluginCatalogKind = z.infer<typeof PluginCatalogKind>
86
+ export const PluginCatalogReference = z.union([
87
+ PluginSavedFamilyReference,
88
+ // Project assemblies retain kind:name; asset tokens retain the underlying library identity.
89
+ z.string().min(1),
90
+ ])
91
+ export type PluginCatalogReference = z.infer<typeof PluginCatalogReference>
92
+
93
+ /** Read-only capability record. Availability is checked again on every mutation. */
94
+ export const PluginCatalogEntry = z.object({
95
+ reference: PluginCatalogReference,
96
+ label: z.string(),
97
+ kind: PluginCatalogKind,
98
+ source: z.enum(["native", "revit", "project", "asset"]),
99
+ createMethods: z.array(z.string()),
100
+ updateMethods: z.array(z.string()),
101
+ requirements: z.array(z.string()),
102
+ unsupportedReason: z.string().optional(),
103
+ parameters: z.array(PluginFamilyDefinitionParameter).optional(),
104
+ /** Parameter keys owned by native placement geometry, never accepted as values overrides. */
105
+ geometryParameters: z.array(z.string()),
106
+ network: NetworkFamilyContract.optional(),
107
+ /** get() includes the native wall recipe without opening a Family Studio draft.
108
+ * Bare recipe lengths use SU; parameter metadata and public values overrides use mm.
109
+ */
110
+ construction: PluginFamilyBundleSchema.optional(),
111
+ })
112
+ export type PluginCatalogEntry = z.infer<typeof PluginCatalogEntry>
113
+ export const PluginCatalogListArgs = z.object({
114
+ kind: PluginCatalogKind.optional(),
115
+ })
116
+ export const PluginCatalogGetArgs = z.object({
117
+ reference: PluginCatalogReference,
118
+ })
119
+
120
+ /** Shared read surface over existing libraries. Does not publish, register, or place definitions. */
121
+ export abstract class PluginDesignCatalogApi {
122
+ /** @param kind Optional element filter. @returns Accessible entries and their supported API paths. */
123
+ abstract list(kind?: PluginCatalogKind): PluginApiReturn<PluginCatalogEntry[]>
124
+ /** @param reference Exact reference from list. @returns The current entry, or null when unavailable. */
125
+ abstract get(
126
+ reference: PluginCatalogReference,
127
+ ): PluginApiReturn<PluginCatalogEntry | null>
128
+ }