fluidcad 0.0.34 → 0.0.35

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 (174) hide show
  1. package/README.md +69 -0
  2. package/bin/commands/login.js +120 -0
  3. package/bin/commands/pack.js +49 -0
  4. package/bin/commands/publish.js +136 -0
  5. package/bin/fluidcad.js +6 -0
  6. package/bin/lib/api-client.js +40 -0
  7. package/bin/lib/browser.js +16 -0
  8. package/bin/lib/config.js +39 -0
  9. package/bin/lib/model-config.js +38 -0
  10. package/bin/lib/workspace.js +57 -0
  11. package/lib/dist/common/shape-factory.d.ts +2 -1
  12. package/lib/dist/common/shape-factory.js +4 -0
  13. package/lib/dist/common/transformable-primitive.d.ts +6 -5
  14. package/lib/dist/common/transformable-primitive.js +8 -7
  15. package/lib/dist/common/vertex.js +0 -1
  16. package/lib/dist/core/2d/aline.d.ts +4 -3
  17. package/lib/dist/core/2d/aline.js +3 -2
  18. package/lib/dist/core/2d/arc.d.ts +3 -2
  19. package/lib/dist/core/2d/arc.js +4 -3
  20. package/lib/dist/core/2d/bezier.d.ts +8 -6
  21. package/lib/dist/core/2d/circle.d.ts +4 -3
  22. package/lib/dist/core/2d/circle.js +3 -2
  23. package/lib/dist/core/2d/ellipse.d.ts +5 -4
  24. package/lib/dist/core/2d/ellipse.js +5 -4
  25. package/lib/dist/core/2d/hline.d.ts +4 -3
  26. package/lib/dist/core/2d/hline.js +5 -3
  27. package/lib/dist/core/2d/line.js +1 -0
  28. package/lib/dist/core/2d/offset.d.ts +3 -2
  29. package/lib/dist/core/2d/offset.js +6 -5
  30. package/lib/dist/core/2d/polygon.d.ts +5 -4
  31. package/lib/dist/core/2d/polygon.js +10 -9
  32. package/lib/dist/core/2d/rect.d.ts +4 -3
  33. package/lib/dist/core/2d/rect.js +10 -9
  34. package/lib/dist/core/2d/slot.d.ts +14 -6
  35. package/lib/dist/core/2d/slot.js +19 -8
  36. package/lib/dist/core/2d/vline.d.ts +4 -3
  37. package/lib/dist/core/2d/vline.js +5 -3
  38. package/lib/dist/core/chamfer.d.ts +5 -4
  39. package/lib/dist/core/chamfer.js +7 -6
  40. package/lib/dist/core/color.d.ts +3 -2
  41. package/lib/dist/core/color.js +2 -1
  42. package/lib/dist/core/cut.d.ts +4 -3
  43. package/lib/dist/core/cut.js +5 -4
  44. package/lib/dist/core/cylinder.d.ts +2 -1
  45. package/lib/dist/core/cylinder.js +2 -1
  46. package/lib/dist/core/draft.d.ts +3 -2
  47. package/lib/dist/core/draft.js +3 -2
  48. package/lib/dist/core/extrude.d.ts +4 -3
  49. package/lib/dist/core/extrude.js +5 -4
  50. package/lib/dist/core/fillet.d.ts +5 -4
  51. package/lib/dist/core/fillet.js +6 -5
  52. package/lib/dist/core/index.d.ts +1 -0
  53. package/lib/dist/core/index.js +1 -0
  54. package/lib/dist/core/interfaces.d.ts +25 -24
  55. package/lib/dist/core/param.d.ts +74 -0
  56. package/lib/dist/core/param.js +147 -0
  57. package/lib/dist/core/repeat.d.ts +2 -1
  58. package/lib/dist/core/repeat.js +10 -8
  59. package/lib/dist/core/revolve.d.ts +2 -1
  60. package/lib/dist/core/revolve.js +3 -2
  61. package/lib/dist/core/rib.d.ts +3 -2
  62. package/lib/dist/core/rib.js +6 -2
  63. package/lib/dist/core/rotate.d.ts +5 -4
  64. package/lib/dist/core/rotate.js +4 -3
  65. package/lib/dist/core/shell.d.ts +3 -2
  66. package/lib/dist/core/shell.js +3 -2
  67. package/lib/dist/core/sphere.d.ts +3 -2
  68. package/lib/dist/core/sphere.js +2 -1
  69. package/lib/dist/core/translate.d.ts +7 -6
  70. package/lib/dist/core/translate.js +6 -5
  71. package/lib/dist/features/2d/arc.js +5 -5
  72. package/lib/dist/features/2d/bezier.js +16 -16
  73. package/lib/dist/features/2d/circle.js +4 -0
  74. package/lib/dist/features/2d/ellipse.js +4 -0
  75. package/lib/dist/features/2d/hline.d.ts +3 -0
  76. package/lib/dist/features/2d/hline.js +9 -2
  77. package/lib/dist/features/2d/line.d.ts +3 -0
  78. package/lib/dist/features/2d/line.js +11 -3
  79. package/lib/dist/features/2d/sketch.js +5 -1
  80. package/lib/dist/features/2d/slot.d.ts +5 -0
  81. package/lib/dist/features/2d/slot.js +52 -7
  82. package/lib/dist/features/2d/tarc-to-point-tangent.js +3 -0
  83. package/lib/dist/features/2d/tarc-to-point.js +3 -0
  84. package/lib/dist/features/2d/tarc-with-tangent.js +3 -0
  85. package/lib/dist/features/2d/tarc.js +3 -0
  86. package/lib/dist/features/2d/vline.d.ts +3 -0
  87. package/lib/dist/features/2d/vline.js +9 -2
  88. package/lib/dist/features/copy-circular.d.ts +4 -3
  89. package/lib/dist/features/copy-circular.js +16 -9
  90. package/lib/dist/features/copy-circular2d.js +16 -9
  91. package/lib/dist/features/copy-linear.d.ts +4 -3
  92. package/lib/dist/features/copy-linear.js +18 -12
  93. package/lib/dist/features/copy-linear2d.js +18 -12
  94. package/lib/dist/features/extrude-base.d.ts +4 -3
  95. package/lib/dist/features/extrude-base.js +10 -3
  96. package/lib/dist/features/mirror-shape2d.js +2 -2
  97. package/lib/dist/features/repeat-base.d.ts +13 -0
  98. package/lib/dist/features/repeat-base.js +21 -0
  99. package/lib/dist/features/repeat-circular.d.ts +6 -5
  100. package/lib/dist/features/repeat-circular.js +3 -6
  101. package/lib/dist/features/repeat-linear.d.ts +7 -7
  102. package/lib/dist/features/repeat-linear.js +3 -6
  103. package/lib/dist/index.d.ts +5 -0
  104. package/lib/dist/index.js +8 -1
  105. package/lib/dist/io/file-import.d.ts +7 -0
  106. package/lib/dist/io/file-import.js +30 -10
  107. package/lib/dist/math/lazy-matrix.d.ts +5 -0
  108. package/lib/dist/math/lazy-matrix.js +78 -10
  109. package/lib/dist/oc/boolean-ops.d.ts +2 -2
  110. package/lib/dist/param-registry.d.ts +34 -0
  111. package/lib/dist/param-registry.js +60 -0
  112. package/lib/dist/rendering/mesh-builder.js +2 -1
  113. package/lib/dist/tests/features/copy-circular.test.js +1 -1
  114. package/lib/dist/tests/features/copy-linear.test.js +10 -10
  115. package/lib/dist/tests/features/repeat-user-repro-cache.test.d.ts +1 -0
  116. package/lib/dist/tests/features/repeat-user-repro-cache.test.js +97 -0
  117. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  118. package/llm-docs/api/bezier.md +10 -11
  119. package/llm-docs/api/index.json +1 -1
  120. package/llm-docs/api/types/arc-points.md +2 -2
  121. package/llm-docs/api/types/cut.md +10 -10
  122. package/llm-docs/api/types/extrude.md +10 -10
  123. package/llm-docs/api/types/loft.md +6 -6
  124. package/llm-docs/api/types/revolve.md +6 -6
  125. package/llm-docs/api/types/rib.md +2 -2
  126. package/llm-docs/api/types/slot.md +2 -2
  127. package/llm-docs/api/types/sweep.md +10 -10
  128. package/llm-docs/api/types/transformable.md +14 -14
  129. package/llm-docs/index.json +12 -12
  130. package/mcp/dist/client.d.ts +1 -0
  131. package/mcp/dist/client.js +8 -1
  132. package/mcp/dist/server.js +14 -1
  133. package/mcp/dist/tools/engine.d.ts +16 -0
  134. package/mcp/dist/tools/engine.js +45 -0
  135. package/package.json +9 -3
  136. package/server/dist/api.d.ts +37 -0
  137. package/server/dist/api.js +44 -0
  138. package/server/dist/code-editor.d.ts +64 -0
  139. package/server/dist/code-editor.js +520 -2
  140. package/server/dist/fluidcad-server.d.ts +68 -1
  141. package/server/dist/fluidcad-server.js +224 -88
  142. package/server/dist/host/blocked-imports.d.ts +8 -0
  143. package/server/dist/host/blocked-imports.js +30 -0
  144. package/server/dist/{vite-manager.d.ts → host/local-scene-host.d.ts} +3 -1
  145. package/server/dist/{vite-manager.js → host/local-scene-host.js} +6 -26
  146. package/server/dist/host/scene-host.d.ts +19 -0
  147. package/server/dist/host/scene-host.js +1 -0
  148. package/server/dist/index.js +24 -117
  149. package/server/dist/model-package/capture-params.d.ts +19 -0
  150. package/server/dist/model-package/capture-params.js +42 -0
  151. package/server/dist/model-package/pack.d.ts +23 -0
  152. package/server/dist/model-package/pack.js +229 -0
  153. package/server/dist/model-package/types.d.ts +78 -0
  154. package/server/dist/model-package/types.js +17 -0
  155. package/server/dist/routes/hit-test.d.ts +3 -0
  156. package/server/dist/routes/hit-test.js +17 -0
  157. package/server/dist/routes/pack.d.ts +10 -0
  158. package/server/dist/routes/pack.js +47 -0
  159. package/server/dist/routes/params.d.ts +3 -0
  160. package/server/dist/routes/params.js +75 -0
  161. package/server/dist/routes/sketch-edits.d.ts +3 -0
  162. package/server/dist/routes/sketch-edits.js +542 -0
  163. package/server/dist/routes/timeline.d.ts +3 -0
  164. package/server/dist/routes/timeline.js +49 -0
  165. package/server/dist/server-core.d.ts +53 -0
  166. package/server/dist/server-core.js +147 -0
  167. package/server/dist/ws-protocol.d.ts +101 -2
  168. package/ui/dist/assets/index-CDJmUpFI.css +2 -0
  169. package/ui/dist/assets/index-MRqwG9Vh.js +5417 -0
  170. package/ui/dist/index.html +2 -2
  171. package/server/dist/routes/actions.d.ts +0 -3
  172. package/server/dist/routes/actions.js +0 -309
  173. package/ui/dist/assets/index-BdqrMDRu.js +0 -4946
  174. package/ui/dist/assets/index-DR7c2Qk9.css +0 -2
@@ -5,6 +5,7 @@ import type { EdgeFilterBuilder } from "../filters/edge/edge-filter.js";
5
5
  import type { Matrix4 } from "../math/matrix4.js";
6
6
  import type { AxisLike } from "../math/axis.js";
7
7
  import type { PlaneLike } from "../math/plane.js";
8
+ import type { NumberParam } from "./param.js";
8
9
  export interface ISceneObject {
9
10
  /**
10
11
  * Sets a custom display name for this object, overriding the default type-based name.
@@ -81,15 +82,15 @@ export interface ITransformable extends ISceneObject {
81
82
  * Translate along X.
82
83
  * @param x - Distance along world X.
83
84
  */
84
- translate(x: number): this;
85
+ translate(x: NumberParam): this;
85
86
  /**
86
87
  * Translate along X and Y.
87
88
  */
88
- translate(x: number, y: number): this;
89
+ translate(x: NumberParam, y: NumberParam): this;
89
90
  /**
90
91
  * Translate along X, Y, and Z.
91
92
  */
92
- translate(x: number, y: number, z: number): this;
93
+ translate(x: NumberParam, y: NumberParam, z: NumberParam): this;
93
94
  /**
94
95
  * Translate by a point-like offset in world space.
95
96
  */
@@ -98,13 +99,13 @@ export interface ITransformable extends ISceneObject {
98
99
  * Rotate by an angle around world Z through the origin.
99
100
  * @param angle - Rotation in degrees.
100
101
  */
101
- rotate(angle: number): this;
102
+ rotate(angle: NumberParam): this;
102
103
  /**
103
104
  * Rotate around an axis by an angle.
104
105
  * @param axis - The axis to rotate around. Use `local(...)` to reference a sketch-local axis.
105
106
  * @param angle - Rotation in degrees.
106
107
  */
107
- rotate(axis: AxisLike, angle: number): this;
108
+ rotate(axis: AxisLike, angle: NumberParam): this;
108
109
  /**
109
110
  * Mirror across a plane.
110
111
  */
@@ -157,7 +158,7 @@ export interface IArcPoints extends IExtrudableGeometry {
157
158
  * Positive = CCW, negative = CW.
158
159
  * @param value - The bulge radius.
159
160
  */
160
- radius(value: number): IArcRadius;
161
+ radius(value: NumberParam): IArcRadius;
161
162
  /**
162
163
  * Specifies the circle center point for the arc.
163
164
  * Mutually exclusive with `.radius()`.
@@ -259,7 +260,7 @@ export interface ISlot extends IExtrudableGeometry {
259
260
  * Sets the rotation angle of the slot's primary axis.
260
261
  * @param angle - Rotation in degrees.
261
262
  */
262
- rotate(angle: number): this;
263
+ rotate(angle: NumberParam): this;
263
264
  }
264
265
  export interface IALine extends IGeometry {
265
266
  /**
@@ -400,12 +401,12 @@ export interface IExtrude extends IBooleanOperation {
400
401
  * Applies a draft (taper) angle to the extrusion walls.
401
402
  * @param value - A single angle for uniform draft, or a `[start, end]` tuple for asymmetric draft.
402
403
  */
403
- draft(value: number | [number, number]): this;
404
+ draft(value: NumberParam | [NumberParam, NumberParam]): this;
404
405
  /**
405
406
  * Offsets the end face by a specified distance along the extrusion direction.
406
407
  * @param value - The offset distance.
407
408
  */
408
- endOffset(value: number): this;
409
+ endOffset(value: NumberParam): this;
409
410
  /**
410
411
  * Enables or disables drill mode, which partitions the sketch into face regions
411
412
  * before extruding.
@@ -422,7 +423,7 @@ export interface IExtrude extends IBooleanOperation {
422
423
  * instead of extruding filled faces. Positive values offset outward, negative values offset inward.
423
424
  * @param offset - The wall offset distance. Positive = outward, negative = inward.
424
425
  */
425
- thin(offset: number): this;
426
+ thin(offset: NumberParam): this;
426
427
  /**
427
428
  * Enables thin extrude mode with two offset directions.
428
429
  * The two offsets must go in opposite directions. If both have the same sign,
@@ -430,7 +431,7 @@ export interface IExtrude extends IBooleanOperation {
430
431
  * @param offset1 - The first wall offset distance. Positive = outward, negative = inward.
431
432
  * @param offset2 - The second wall offset distance, in the opposite direction of offset1.
432
433
  */
433
- thin(offset1: number, offset2: number): this;
434
+ thin(offset1: NumberParam, offset2: NumberParam): this;
434
435
  }
435
436
  export interface ICut extends ISceneObject {
436
437
  /**
@@ -447,12 +448,12 @@ export interface ICut extends ISceneObject {
447
448
  * Applies a draft (taper) angle to the cut walls.
448
449
  * @param value - A single angle for uniform draft, or a `[start, end]` tuple for asymmetric draft.
449
450
  */
450
- draft(value: number | [number, number]): this;
451
+ draft(value: NumberParam | [NumberParam, NumberParam]): this;
451
452
  /**
452
453
  * Offsets the cut end face by a specified distance along the cut direction.
453
454
  * @param value - The offset distance.
454
455
  */
455
- endOffset(value: number): this;
456
+ endOffset(value: NumberParam): this;
456
457
  /**
457
458
  * Selects edges at the start of the cut path, classified by signed distance from the cut plane.
458
459
  * @param args - Numeric indices or {@link EdgeFilterBuilder} instances to filter the selection.
@@ -483,7 +484,7 @@ export interface ICut extends ISceneObject {
483
484
  * instead of cutting filled faces. Positive values offset outward, negative values offset inward.
484
485
  * @param offset - The wall offset distance. Positive = outward, negative = inward.
485
486
  */
486
- thin(offset: number): this;
487
+ thin(offset: NumberParam): this;
487
488
  /**
488
489
  * Enables thin cut mode with two offset directions.
489
490
  * The two offsets must go in opposite directions. If both have the same sign,
@@ -491,7 +492,7 @@ export interface ICut extends ISceneObject {
491
492
  * @param offset1 - The first wall offset distance. Positive = outward, negative = inward.
492
493
  * @param offset2 - The second wall offset distance, in the opposite direction of offset1.
493
494
  */
494
- thin(offset1: number, offset2: number): this;
495
+ thin(offset1: NumberParam, offset2: NumberParam): this;
495
496
  }
496
497
  export interface IRevolve extends IBooleanOperation {
497
498
  /**
@@ -509,7 +510,7 @@ export interface IRevolve extends IBooleanOperation {
509
510
  * outward, negative values offset inward.
510
511
  * @param offset - The wall offset distance. Positive = outward, negative = inward.
511
512
  */
512
- thin(offset: number): this;
513
+ thin(offset: NumberParam): this;
513
514
  /**
514
515
  * Enables thin revolve mode with two offset directions.
515
516
  * The two offsets must go in opposite directions. If both have the same sign,
@@ -517,7 +518,7 @@ export interface IRevolve extends IBooleanOperation {
517
518
  * @param offset1 - The first wall offset distance. Positive = outward, negative = inward.
518
519
  * @param offset2 - The second wall offset distance, in the opposite direction of offset1.
519
520
  */
520
- thin(offset1: number, offset2: number): this;
521
+ thin(offset1: NumberParam, offset2: NumberParam): this;
521
522
  /**
522
523
  * Selects faces created inside the solid during revolution (e.g., the inner
523
524
  * wall of a thin-walled revolve from a closed profile).
@@ -578,7 +579,7 @@ export interface ILoft extends IBooleanOperation {
578
579
  * and share the same topology. Positive values offset outward, negative offsets inward.
579
580
  * @param offset - The wall offset distance. Positive = outward, negative = inward.
580
581
  */
581
- thin(offset: number): this;
582
+ thin(offset: NumberParam): this;
582
583
  /**
583
584
  * Enables thin loft mode with two offset directions.
584
585
  * The two offsets must go in opposite directions. If both have the same sign,
@@ -586,7 +587,7 @@ export interface ILoft extends IBooleanOperation {
586
587
  * @param offset1 - The first wall offset distance. Positive = outward, negative = inward.
587
588
  * @param offset2 - The second wall offset distance, in the opposite direction of offset1.
588
589
  */
589
- thin(offset1: number, offset2: number): this;
590
+ thin(offset1: NumberParam, offset2: NumberParam): this;
590
591
  /**
591
592
  * Selects faces created inside the solid during loft (e.g., the inner
592
593
  * wall of a thin-walled loft from closed profiles).
@@ -655,12 +656,12 @@ export interface ISweep extends IBooleanOperation {
655
656
  * Applies a draft (taper) angle to the sweep walls.
656
657
  * @param value - A single angle for uniform draft, or a `[start, end]` tuple for asymmetric draft.
657
658
  */
658
- draft(value: number | [number, number]): this;
659
+ draft(value: NumberParam | [NumberParam, NumberParam]): this;
659
660
  /**
660
661
  * Offsets the end face by a specified distance along the sweep direction.
661
662
  * @param value - The offset distance.
662
663
  */
663
- endOffset(value: number): this;
664
+ endOffset(value: NumberParam): this;
664
665
  /**
665
666
  * Enables or disables drill mode.
666
667
  * @param value - `true` to enable (default), `false` to disable.
@@ -677,7 +678,7 @@ export interface ISweep extends IBooleanOperation {
677
678
  * negative values offset inward.
678
679
  * @param offset - The wall offset distance. Positive = outward, negative = inward.
679
680
  */
680
- thin(offset: number): this;
681
+ thin(offset: NumberParam): this;
681
682
  /**
682
683
  * Enables thin sweep mode with two offset directions.
683
684
  * The two offsets must go in opposite directions. If both have the same sign,
@@ -685,7 +686,7 @@ export interface ISweep extends IBooleanOperation {
685
686
  * @param offset1 - The first wall offset distance. Positive = outward, negative = inward.
686
687
  * @param offset2 - The second wall offset distance, in the opposite direction of offset1.
687
688
  */
688
- thin(offset1: number, offset2: number): this;
689
+ thin(offset1: NumberParam, offset2: NumberParam): this;
689
690
  /**
690
691
  * Selects the cap faces at the open ends of a thin-walled sweep from an open profile.
691
692
  * These are the small faces connecting the inner and outer walls at the profile endpoints.
@@ -781,7 +782,7 @@ export interface IRib extends IBooleanOperation {
781
782
  * Applies a draft (taper) angle to the rib walls.
782
783
  * @param value - A single angle for uniform draft, or a `[start, end]` tuple for asymmetric draft.
783
784
  */
784
- draft(value: number | [number, number]): this;
785
+ draft(value: NumberParam | [NumberParam, NumberParam]): this;
785
786
  /**
786
787
  * Switches the extrusion direction to parallel to the sketch plane
787
788
  * (perpendicular to the spine within the plane) instead of normal to it.
@@ -0,0 +1,74 @@
1
+ import { type MultiControlType, type SelectOption } from "../param-registry.js";
2
+ export type ParamType = 'number' | 'slider' | 'text' | 'select' | 'checkbox' | 'color';
3
+ interface BaseParamOptions {
4
+ group?: string;
5
+ description?: string;
6
+ }
7
+ export interface NumberParamOptions extends BaseParamOptions {
8
+ min?: number;
9
+ max?: number;
10
+ step?: number;
11
+ }
12
+ export interface SliderParamOptions extends BaseParamOptions {
13
+ min?: number;
14
+ max?: number;
15
+ step?: number;
16
+ }
17
+ export interface SelectParamOptions extends BaseParamOptions {
18
+ options: SelectOption[];
19
+ multi?: boolean;
20
+ multiControlType?: MultiControlType;
21
+ }
22
+ export type CheckboxParamOptions = BaseParamOptions;
23
+ export type TextParamOptions = BaseParamOptions;
24
+ export type ColorParamOptions = BaseParamOptions;
25
+ export interface ParamOptionsMap {
26
+ number: NumberParamOptions;
27
+ slider: SliderParamOptions;
28
+ select: SelectParamOptions;
29
+ checkbox: CheckboxParamOptions;
30
+ text: TextParamOptions;
31
+ color: ColorParamOptions;
32
+ }
33
+ /** @deprecated Use `param()` with a `ParamOptions` object instead. */
34
+ export declare class ParamValue<T extends string | number | boolean> {
35
+ private _value;
36
+ private _definition;
37
+ constructor(label: string, defaultValue: T);
38
+ slider(opts?: {
39
+ min?: number;
40
+ max?: number;
41
+ step?: number;
42
+ }): this;
43
+ number(opts?: {
44
+ min?: number;
45
+ max?: number;
46
+ step?: number;
47
+ }): this;
48
+ text(): this;
49
+ checkbox(): this;
50
+ select(items: SelectOption[], opts?: {
51
+ multi?: boolean;
52
+ multiControlType?: MultiControlType;
53
+ }): this;
54
+ description(desc: string): this;
55
+ group(name: string): this;
56
+ valueOf(): T;
57
+ toString(): string;
58
+ toJSON(): T;
59
+ [Symbol.toPrimitive](hint: string): T | string;
60
+ }
61
+ export type NumberParam = number | ParamValue<number>;
62
+ export type StringParam = string | ParamValue<string>;
63
+ export type BooleanParam = boolean | ParamValue<boolean>;
64
+ export declare function isNumberParam(v: unknown): v is NumberParam;
65
+ export declare function isBooleanParam(v: unknown): v is BooleanParam;
66
+ export declare function resolveParam(v: NumberParam): number;
67
+ export declare function resolveParam(v: StringParam): string;
68
+ export declare function resolveParam(v: BooleanParam): boolean;
69
+ export default function param<T extends string | number | boolean>(label: string, defaultValue: T): T;
70
+ export default function param<T extends string | number | boolean, K extends ParamType>(label: string, defaultValue: T, type: K, options?: ParamOptionsMap[K]): T;
71
+ export default function param(label: string, defaultValue: (string | number)[], type: 'select', options: SelectParamOptions & {
72
+ multi: true;
73
+ }): (string | number)[];
74
+ export {};
@@ -0,0 +1,147 @@
1
+ import { getParamRegistry } from "../param-registry.js";
2
+ /** @deprecated Use `param()` with a `ParamOptions` object instead. */
3
+ export class ParamValue {
4
+ _value;
5
+ _definition;
6
+ constructor(label, defaultValue) {
7
+ const registry = getParamRegistry();
8
+ this._value = registry.resolve(label, defaultValue);
9
+ this._definition = {
10
+ label,
11
+ defaultValue,
12
+ currentValue: this._value,
13
+ controlType: typeof defaultValue === 'boolean' ? 'checkbox'
14
+ : typeof defaultValue === 'number' ? 'number'
15
+ : 'text',
16
+ };
17
+ registry.register(this._definition);
18
+ }
19
+ slider(opts) {
20
+ this._definition.controlType = 'slider';
21
+ if (opts) {
22
+ if (opts.min != null) {
23
+ this._definition.min = opts.min;
24
+ }
25
+ if (opts.max != null) {
26
+ this._definition.max = opts.max;
27
+ }
28
+ if (opts.step != null) {
29
+ this._definition.step = opts.step;
30
+ }
31
+ }
32
+ return this;
33
+ }
34
+ number(opts) {
35
+ this._definition.controlType = 'number';
36
+ if (opts) {
37
+ if (opts.min != null) {
38
+ this._definition.min = opts.min;
39
+ }
40
+ if (opts.max != null) {
41
+ this._definition.max = opts.max;
42
+ }
43
+ if (opts.step != null) {
44
+ this._definition.step = opts.step;
45
+ }
46
+ }
47
+ return this;
48
+ }
49
+ text() {
50
+ this._definition.controlType = 'text';
51
+ return this;
52
+ }
53
+ checkbox() {
54
+ this._definition.controlType = 'checkbox';
55
+ return this;
56
+ }
57
+ select(items, opts) {
58
+ this._definition.controlType = 'select';
59
+ this._definition.options = items;
60
+ if (opts?.multi) {
61
+ this._definition.multi = true;
62
+ }
63
+ if (opts?.multiControlType) {
64
+ this._definition.multiControlType = opts.multiControlType;
65
+ }
66
+ return this;
67
+ }
68
+ description(desc) {
69
+ this._definition.description = desc;
70
+ return this;
71
+ }
72
+ group(name) {
73
+ this._definition.group = name;
74
+ return this;
75
+ }
76
+ valueOf() {
77
+ return this._value;
78
+ }
79
+ toString() {
80
+ return String(this._value);
81
+ }
82
+ toJSON() {
83
+ return this._value;
84
+ }
85
+ [Symbol.toPrimitive](hint) {
86
+ if (hint === 'string') {
87
+ return String(this._value);
88
+ }
89
+ return this._value;
90
+ }
91
+ }
92
+ export function isNumberParam(v) {
93
+ return typeof v === 'number' || (v instanceof ParamValue && typeof v.valueOf() === 'number');
94
+ }
95
+ export function isBooleanParam(v) {
96
+ return typeof v === 'boolean' || (v instanceof ParamValue && typeof v.valueOf() === 'boolean');
97
+ }
98
+ export function resolveParam(v) {
99
+ if (v instanceof ParamValue) {
100
+ return v.valueOf();
101
+ }
102
+ return v;
103
+ }
104
+ export default function param(label, defaultValue, type, options) {
105
+ const registry = getParamRegistry();
106
+ const value = Array.isArray(defaultValue)
107
+ ? registry.resolve(label, defaultValue)
108
+ : registry.resolve(label, defaultValue);
109
+ const controlType = type
110
+ ?? (typeof defaultValue === 'boolean' ? 'checkbox'
111
+ : typeof defaultValue === 'number' ? 'number'
112
+ : 'text');
113
+ const definition = {
114
+ label,
115
+ defaultValue,
116
+ currentValue: value,
117
+ controlType,
118
+ };
119
+ if (options) {
120
+ if ('group' in options && options.group != null) {
121
+ definition.group = options.group;
122
+ }
123
+ if ('description' in options && options.description != null) {
124
+ definition.description = options.description;
125
+ }
126
+ if ('min' in options && options.min != null) {
127
+ definition.min = options.min;
128
+ }
129
+ if ('max' in options && options.max != null) {
130
+ definition.max = options.max;
131
+ }
132
+ if ('step' in options && options.step != null) {
133
+ definition.step = options.step;
134
+ }
135
+ if ('options' in options && options.options != null) {
136
+ definition.options = options.options;
137
+ }
138
+ if ('multi' in options && options.multi != null) {
139
+ definition.multi = options.multi;
140
+ }
141
+ if ('multiControlType' in options && options.multiControlType != null) {
142
+ definition.multiControlType = options.multiControlType;
143
+ }
144
+ }
145
+ registry.register(definition);
146
+ return value;
147
+ }
@@ -3,6 +3,7 @@ import { Matrix4 } from "../math/matrix4.js";
3
3
  import { LinearRepeatOptions } from "../features/repeat-linear.js";
4
4
  import { CircularRepeatOptions } from "../features/repeat-circular.js";
5
5
  import { ISceneObject } from "./interfaces.js";
6
+ import { type NumberParam } from "./param.js";
6
7
  import { PlaneLike } from "../math/plane.js";
7
8
  export type RepeatType = 'linear' | 'circular' | 'mirror' | 'rotate';
8
9
  interface RepeatFunction {
@@ -44,7 +45,7 @@ interface RepeatFunction {
44
45
  * @param angle - The rotation angle in degrees (defaults to 90)
45
46
  * @param objects - The objects to rotate (defaults to last object)
46
47
  */
47
- (type: 'rotate', axis: AxisLike, angle?: number, ...objects: ISceneObject[]): ISceneObject;
48
+ (type: 'rotate', axis: AxisLike, angle?: NumberParam, ...objects: ISceneObject[]): ISceneObject;
48
49
  /**
49
50
  * Creates a transformed clone of objects using an arbitrary matrix.
50
51
  * @param matrix - The transformation matrix to apply
@@ -7,6 +7,7 @@ import { rad } from "../helpers/math-helpers.js";
7
7
  import { RepeatLinear } from "../features/repeat-linear.js";
8
8
  import { RepeatCircular } from "../features/repeat-circular.js";
9
9
  import { cloneWithTransform } from "../helpers/clone-transform.js";
10
+ import { isNumberParam, resolveParam } from "./param.js";
10
11
  import { MirrorFeature } from "../features/mirror-feature.js";
11
12
  import { RepeatMatrix } from "../features/repeat-matrix.js";
12
13
  import { resolveAxis, resolvePlane } from "../helpers/resolve.js";
@@ -66,12 +67,12 @@ function build(context) {
66
67
  ? restObjects
67
68
  : [context.getSceneObjects().at(-1)];
68
69
  if (type === 'linear') {
69
- const counts = Array.isArray(options.count) ? options.count : [options.count];
70
+ const counts = Array.isArray(options.count) ? options.count : [resolveParam(options.count)];
70
71
  const offsets = options.offset != null
71
- ? (Array.isArray(options.offset) ? options.offset : [options.offset])
72
+ ? (Array.isArray(options.offset) ? options.offset : [resolveParam(options.offset)])
72
73
  : null;
73
74
  const lengths = 'length' in options && options.length != null
74
- ? (Array.isArray(options.length) ? options.length : [options.length])
75
+ ? (Array.isArray(options.length) ? options.length : [resolveParam(options.length)])
75
76
  : null;
76
77
  const repeat = new RepeatLinear(axisSources, options, objects);
77
78
  const transformedObjects = [];
@@ -139,14 +140,15 @@ function build(context) {
139
140
  if (type === 'circular') {
140
141
  const axis = axisSources[0];
141
142
  const circularOptions = options;
142
- const { count, centered, skip } = circularOptions;
143
+ const count = resolveParam(circularOptions.count);
144
+ const { centered, skip } = circularOptions;
143
145
  const repeat = new RepeatCircular(axis, circularOptions, objects);
144
146
  let offset;
145
147
  if ('offset' in circularOptions && circularOptions.offset !== undefined) {
146
- offset = circularOptions.offset;
148
+ offset = resolveParam(circularOptions.offset);
147
149
  }
148
150
  else {
149
- const angle = circularOptions.angle;
151
+ const angle = resolveParam(circularOptions.angle);
150
152
  offset = angle % 360 === 0 ? angle / count : angle / (count - 1);
151
153
  }
152
154
  const startOffset = centered ? -(count * offset) / 2 : 0;
@@ -183,8 +185,8 @@ function build(context) {
183
185
  const axisArg = args[1];
184
186
  let angle = 90;
185
187
  let restStart = 2;
186
- if (typeof args[2] === 'number') {
187
- angle = args[2];
188
+ if (isNumberParam(args[2])) {
189
+ angle = resolveParam(args[2]);
188
190
  restStart = 3;
189
191
  }
190
192
  const restObjects = args.slice(restStart);
@@ -1,5 +1,6 @@
1
1
  import { AxisLike } from "../math/axis.js";
2
2
  import { IRevolve, ISceneObject } from "./interfaces.js";
3
+ import { type NumberParam } from "./param.js";
3
4
  interface RevolveFunction {
4
5
  /**
5
6
  * Revolves the last sketch 360 degrees around an axis.
@@ -13,7 +14,7 @@ interface RevolveFunction {
13
14
  * @param angle - The sweep angle in degrees
14
15
  * @param target - The sketch to revolve
15
16
  */
16
- (axisLike: AxisLike, angle: number, target?: ISceneObject): IRevolve;
17
+ (axisLike: AxisLike, angle: NumberParam, target?: ISceneObject): IRevolve;
17
18
  }
18
19
  declare const _default: RevolveFunction;
19
20
  export default _default;
@@ -2,6 +2,7 @@ import { registerBuilder } from "../index.js";
2
2
  import { Revolve } from "../features/revolve.js";
3
3
  import { resolveAxis } from "../helpers/resolve.js";
4
4
  import { SceneObject } from "../common/scene-object.js";
5
+ import { isNumberParam, resolveParam } from "./param.js";
5
6
  function isExtrudable(obj) {
6
7
  return obj instanceof SceneObject && obj.isExtrudable();
7
8
  }
@@ -16,8 +17,8 @@ function build(context) {
16
17
  // (axis, angle)
17
18
  if (params.length === 2) {
18
19
  const axis = resolveAxis(params[0], context);
19
- if (typeof params[1] === 'number') {
20
- return new Revolve(axis, params[1], extrudable);
20
+ if (isNumberParam(params[1])) {
21
+ return new Revolve(axis, resolveParam(params[1]), extrudable);
21
22
  }
22
23
  }
23
24
  throw new Error("Invalid parameters for revolve function.");
@@ -1,4 +1,5 @@
1
1
  import { IRib, ISceneObject } from "./interfaces.js";
2
+ import { type NumberParam } from "./param.js";
2
3
  interface RibFunction {
3
4
  /**
4
5
  * Creates a rib from the last sketch with the given thickness.
@@ -6,13 +7,13 @@ interface RibFunction {
6
7
  * surrounding solids. Positive thickness = forward, negative = reverse.
7
8
  * @param thickness - Wall thickness (sign controls direction)
8
9
  */
9
- (thickness: number): IRib;
10
+ (thickness: NumberParam): IRib;
10
11
  /**
11
12
  * Creates a rib from an explicit sketch spine with the given thickness.
12
13
  * @param thickness - Wall thickness (sign controls direction)
13
14
  * @param spine - The sketch providing the rib spine wire and plane
14
15
  */
15
- (thickness: number, spine: ISceneObject): IRib;
16
+ (thickness: NumberParam, spine: ISceneObject): IRib;
16
17
  }
17
18
  declare const _default: RibFunction;
18
19
  export default _default;
@@ -1,6 +1,7 @@
1
1
  import { SceneObject } from "../common/scene-object.js";
2
2
  import { registerBuilder } from "../index.js";
3
3
  import { Rib } from "../features/rib.js";
4
+ import { isNumberParam, resolveParam } from "./param.js";
4
5
  function isExtrudable(obj) {
5
6
  return obj instanceof SceneObject && obj.isExtrudable();
6
7
  }
@@ -11,8 +12,11 @@ function build(context) {
11
12
  if (args.length === 0) {
12
13
  throw new Error("rib() requires at least a thickness argument.");
13
14
  }
14
- const thickness = args[0];
15
- if (typeof thickness !== 'number' || thickness === 0) {
15
+ if (!isNumberParam(args[0])) {
16
+ throw new Error("rib() thickness must be a non-zero number.");
17
+ }
18
+ const thickness = resolveParam(args[0]);
19
+ if (thickness === 0) {
16
20
  throw new Error("rib() thickness must be a non-zero number.");
17
21
  }
18
22
  let spine;
@@ -1,26 +1,27 @@
1
1
  import { AxisLike } from "../math/axis.js";
2
2
  import { IRotate, ISceneObject } from "./interfaces.js";
3
+ import { type NumberParam, type BooleanParam } from "./param.js";
3
4
  interface RotateFunction {
4
5
  /**
5
6
  * [2D] Rotates geometry by an angle inside a sketch.
6
7
  * @param angle - The rotation angle in degrees
7
8
  * @param targets - The geometries to rotate (defaults to last object)
8
9
  */
9
- (angle: number, ...targets: ISceneObject[]): IRotate;
10
+ (angle: NumberParam, ...targets: ISceneObject[]): IRotate;
10
11
  /**
11
12
  * [2D] Rotates geometry by an angle inside a sketch, optionally making a copy.
12
13
  * @param angle - The rotation angle in degrees
13
14
  * @param copy - Whether to copy instead of move
14
15
  * @param targets - The geometries to rotate (defaults to last object)
15
16
  */
16
- (angle: number, copy: boolean, ...targets: ISceneObject[]): IRotate;
17
+ (angle: NumberParam, copy: BooleanParam, ...targets: ISceneObject[]): IRotate;
17
18
  /**
18
19
  * [3D] Rotates objects around an axis by an angle.
19
20
  * @param axis - The axis to rotate around
20
21
  * @param angle - The rotation angle in degrees
21
22
  * @param targets - The objects to rotate (defaults to last object)
22
23
  */
23
- (axis: AxisLike, angle: number, ...targets: ISceneObject[]): IRotate;
24
+ (axis: AxisLike, angle: NumberParam, ...targets: ISceneObject[]): IRotate;
24
25
  /**
25
26
  * [3D] Rotates objects around an axis by an angle, optionally making a copy.
26
27
  * @param axis - The axis to rotate around
@@ -28,7 +29,7 @@ interface RotateFunction {
28
29
  * @param copy - Whether to copy instead of move
29
30
  * @param targets - The objects to rotate (defaults to last object)
30
31
  */
31
- (axis: AxisLike, angle: number, copy: boolean, ...targets: ISceneObject[]): IRotate;
32
+ (axis: AxisLike, angle: NumberParam, copy: BooleanParam, ...targets: ISceneObject[]): IRotate;
32
33
  }
33
34
  declare const _default: RotateFunction;
34
35
  export default _default;
@@ -5,6 +5,7 @@ import { SceneObject } from "../common/scene-object.js";
5
5
  import { AxisObjectBase } from "../features/axis-renderable-base.js";
6
6
  import { AxisObject } from "../features/axis.js";
7
7
  import { Rotate2D } from "../features/rotate2d.js";
8
+ import { isBooleanParam, resolveParam } from "./param.js";
8
9
  function build(context) {
9
10
  return function rotate() {
10
11
  const args = Array.from(arguments);
@@ -15,13 +16,13 @@ function build(context) {
15
16
  targets.unshift(args.pop());
16
17
  }
17
18
  // Extract copy flag from the end (if boolean)
18
- const copy = typeof args[args.length - 1] === 'boolean' ? args.pop() : false;
19
+ const copy = isBooleanParam(args[args.length - 1]) ? resolveParam(args.pop()) : false;
19
20
  // 2D: rotate(angle, copy?, ...targets)
20
21
  if (args.length === 1) {
21
22
  if (!activeSketch) {
22
23
  throw new Error("rotate(angle) is only valid inside a sketch. For 3D rotation, specify an axis: rotate(axis, angle).");
23
24
  }
24
- const angle = args[0];
25
+ const angle = resolveParam(args[0]);
25
26
  const rotate = new Rotate2D(angle, copy, ...targets);
26
27
  context.addSceneObject(rotate);
27
28
  return rotate;
@@ -40,7 +41,7 @@ function build(context) {
40
41
  axis = new AxisObject(a);
41
42
  context.addSceneObject(axis);
42
43
  }
43
- const angle = args[1];
44
+ const angle = resolveParam(args[1]);
44
45
  const rotate = new Rotate(axis, angle, copy, ...targets);
45
46
  context.addSceneObject(rotate);
46
47
  return rotate;
@@ -1,16 +1,17 @@
1
1
  import { ISceneObject, IShell } from "./interfaces.js";
2
+ import { type NumberParam } from "./param.js";
2
3
  interface ShellFunction {
3
4
  /**
4
5
  * Hollows out a solid with the given wall thickness.
5
6
  * @param thickness - The wall thickness (defaults to 2.5)
6
7
  */
7
- (thickness?: number): IShell;
8
+ (thickness?: NumberParam): IShell;
8
9
  /**
9
10
  * Hollows out a solid, removing the selected faces.
10
11
  * @param thickness - The wall thickness
11
12
  * @param selections - The face selections to remove
12
13
  */
13
- (thickness: number, ...selections: ISceneObject[]): IShell;
14
+ (thickness: NumberParam, ...selections: ISceneObject[]): IShell;
14
15
  }
15
16
  declare const _default: ShellFunction;
16
17
  export default _default;