fluidcad 0.0.34 → 0.0.36

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 (176) hide show
  1. package/README.md +69 -0
  2. package/bin/commands/login.js +148 -0
  3. package/bin/commands/mcp.js +3 -2
  4. package/bin/commands/pack.js +49 -0
  5. package/bin/commands/publish.js +231 -0
  6. package/bin/fluidcad.js +6 -0
  7. package/bin/lib/api-client.js +48 -0
  8. package/bin/lib/browser.js +16 -0
  9. package/bin/lib/config.js +39 -0
  10. package/bin/lib/model-config.js +61 -0
  11. package/bin/lib/prompt.js +97 -0
  12. package/bin/lib/workspace.js +57 -0
  13. package/lib/dist/common/shape-factory.d.ts +2 -1
  14. package/lib/dist/common/shape-factory.js +4 -0
  15. package/lib/dist/common/transformable-primitive.d.ts +6 -5
  16. package/lib/dist/common/transformable-primitive.js +8 -7
  17. package/lib/dist/common/vertex.js +0 -1
  18. package/lib/dist/core/2d/aline.d.ts +4 -3
  19. package/lib/dist/core/2d/aline.js +3 -2
  20. package/lib/dist/core/2d/arc.d.ts +3 -2
  21. package/lib/dist/core/2d/arc.js +4 -3
  22. package/lib/dist/core/2d/bezier.d.ts +8 -6
  23. package/lib/dist/core/2d/circle.d.ts +4 -3
  24. package/lib/dist/core/2d/circle.js +3 -2
  25. package/lib/dist/core/2d/ellipse.d.ts +5 -4
  26. package/lib/dist/core/2d/ellipse.js +5 -4
  27. package/lib/dist/core/2d/hline.d.ts +4 -3
  28. package/lib/dist/core/2d/hline.js +5 -3
  29. package/lib/dist/core/2d/line.js +1 -0
  30. package/lib/dist/core/2d/offset.d.ts +3 -2
  31. package/lib/dist/core/2d/offset.js +6 -5
  32. package/lib/dist/core/2d/polygon.d.ts +5 -4
  33. package/lib/dist/core/2d/polygon.js +10 -9
  34. package/lib/dist/core/2d/rect.d.ts +4 -3
  35. package/lib/dist/core/2d/rect.js +10 -9
  36. package/lib/dist/core/2d/slot.d.ts +14 -6
  37. package/lib/dist/core/2d/slot.js +19 -8
  38. package/lib/dist/core/2d/vline.d.ts +4 -3
  39. package/lib/dist/core/2d/vline.js +5 -3
  40. package/lib/dist/core/chamfer.d.ts +5 -4
  41. package/lib/dist/core/chamfer.js +7 -6
  42. package/lib/dist/core/color.d.ts +3 -2
  43. package/lib/dist/core/color.js +2 -1
  44. package/lib/dist/core/cut.d.ts +4 -3
  45. package/lib/dist/core/cut.js +5 -4
  46. package/lib/dist/core/cylinder.d.ts +2 -1
  47. package/lib/dist/core/cylinder.js +2 -1
  48. package/lib/dist/core/draft.d.ts +3 -2
  49. package/lib/dist/core/draft.js +3 -2
  50. package/lib/dist/core/extrude.d.ts +4 -3
  51. package/lib/dist/core/extrude.js +5 -4
  52. package/lib/dist/core/fillet.d.ts +5 -4
  53. package/lib/dist/core/fillet.js +6 -5
  54. package/lib/dist/core/index.d.ts +1 -0
  55. package/lib/dist/core/index.js +1 -0
  56. package/lib/dist/core/interfaces.d.ts +25 -24
  57. package/lib/dist/core/param.d.ts +74 -0
  58. package/lib/dist/core/param.js +147 -0
  59. package/lib/dist/core/repeat.d.ts +2 -1
  60. package/lib/dist/core/repeat.js +10 -8
  61. package/lib/dist/core/revolve.d.ts +2 -1
  62. package/lib/dist/core/revolve.js +3 -2
  63. package/lib/dist/core/rib.d.ts +3 -2
  64. package/lib/dist/core/rib.js +6 -2
  65. package/lib/dist/core/rotate.d.ts +5 -4
  66. package/lib/dist/core/rotate.js +4 -3
  67. package/lib/dist/core/shell.d.ts +3 -2
  68. package/lib/dist/core/shell.js +3 -2
  69. package/lib/dist/core/sphere.d.ts +3 -2
  70. package/lib/dist/core/sphere.js +2 -1
  71. package/lib/dist/core/translate.d.ts +7 -6
  72. package/lib/dist/core/translate.js +6 -5
  73. package/lib/dist/features/2d/arc.js +5 -5
  74. package/lib/dist/features/2d/bezier.js +16 -16
  75. package/lib/dist/features/2d/circle.js +4 -0
  76. package/lib/dist/features/2d/ellipse.js +4 -0
  77. package/lib/dist/features/2d/hline.d.ts +3 -0
  78. package/lib/dist/features/2d/hline.js +9 -2
  79. package/lib/dist/features/2d/line.d.ts +3 -0
  80. package/lib/dist/features/2d/line.js +11 -3
  81. package/lib/dist/features/2d/sketch.js +5 -1
  82. package/lib/dist/features/2d/slot.d.ts +5 -0
  83. package/lib/dist/features/2d/slot.js +52 -7
  84. package/lib/dist/features/2d/tarc-to-point-tangent.js +3 -0
  85. package/lib/dist/features/2d/tarc-to-point.js +3 -0
  86. package/lib/dist/features/2d/tarc-with-tangent.js +3 -0
  87. package/lib/dist/features/2d/tarc.js +3 -0
  88. package/lib/dist/features/2d/vline.d.ts +3 -0
  89. package/lib/dist/features/2d/vline.js +9 -2
  90. package/lib/dist/features/copy-circular.d.ts +4 -3
  91. package/lib/dist/features/copy-circular.js +16 -9
  92. package/lib/dist/features/copy-circular2d.js +16 -9
  93. package/lib/dist/features/copy-linear.d.ts +4 -3
  94. package/lib/dist/features/copy-linear.js +18 -12
  95. package/lib/dist/features/copy-linear2d.js +18 -12
  96. package/lib/dist/features/extrude-base.d.ts +4 -3
  97. package/lib/dist/features/extrude-base.js +10 -3
  98. package/lib/dist/features/mirror-shape2d.js +2 -2
  99. package/lib/dist/features/repeat-base.d.ts +13 -0
  100. package/lib/dist/features/repeat-base.js +21 -0
  101. package/lib/dist/features/repeat-circular.d.ts +6 -5
  102. package/lib/dist/features/repeat-circular.js +3 -6
  103. package/lib/dist/features/repeat-linear.d.ts +7 -7
  104. package/lib/dist/features/repeat-linear.js +3 -6
  105. package/lib/dist/index.d.ts +5 -0
  106. package/lib/dist/index.js +8 -1
  107. package/lib/dist/io/file-import.d.ts +7 -0
  108. package/lib/dist/io/file-import.js +30 -10
  109. package/lib/dist/math/lazy-matrix.d.ts +5 -0
  110. package/lib/dist/math/lazy-matrix.js +78 -10
  111. package/lib/dist/oc/boolean-ops.d.ts +2 -2
  112. package/lib/dist/param-registry.d.ts +34 -0
  113. package/lib/dist/param-registry.js +60 -0
  114. package/lib/dist/rendering/mesh-builder.js +2 -1
  115. package/lib/dist/tests/features/copy-circular.test.js +1 -1
  116. package/lib/dist/tests/features/copy-linear.test.js +10 -10
  117. package/lib/dist/tests/features/repeat-user-repro-cache.test.d.ts +1 -0
  118. package/lib/dist/tests/features/repeat-user-repro-cache.test.js +97 -0
  119. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  120. package/llm-docs/api/bezier.md +10 -11
  121. package/llm-docs/api/index.json +1 -1
  122. package/llm-docs/api/types/arc-points.md +2 -2
  123. package/llm-docs/api/types/cut.md +10 -10
  124. package/llm-docs/api/types/extrude.md +10 -10
  125. package/llm-docs/api/types/loft.md +6 -6
  126. package/llm-docs/api/types/revolve.md +6 -6
  127. package/llm-docs/api/types/rib.md +2 -2
  128. package/llm-docs/api/types/slot.md +2 -2
  129. package/llm-docs/api/types/sweep.md +10 -10
  130. package/llm-docs/api/types/transformable.md +14 -14
  131. package/llm-docs/index.json +12 -12
  132. package/mcp/dist/client.d.ts +1 -0
  133. package/mcp/dist/client.js +8 -1
  134. package/mcp/dist/server.js +14 -1
  135. package/mcp/dist/tools/engine.d.ts +16 -0
  136. package/mcp/dist/tools/engine.js +45 -0
  137. package/package.json +9 -3
  138. package/server/dist/api.d.ts +37 -0
  139. package/server/dist/api.js +44 -0
  140. package/server/dist/code-editor.d.ts +64 -0
  141. package/server/dist/code-editor.js +520 -2
  142. package/server/dist/fluidcad-server.d.ts +87 -1
  143. package/server/dist/fluidcad-server.js +254 -88
  144. package/server/dist/host/blocked-imports.d.ts +8 -0
  145. package/server/dist/host/blocked-imports.js +30 -0
  146. package/server/dist/{vite-manager.d.ts → host/local-scene-host.d.ts} +3 -1
  147. package/server/dist/{vite-manager.js → host/local-scene-host.js} +6 -26
  148. package/server/dist/host/scene-host.d.ts +19 -0
  149. package/server/dist/host/scene-host.js +1 -0
  150. package/server/dist/index.js +24 -117
  151. package/server/dist/model-package/capture-params.d.ts +19 -0
  152. package/server/dist/model-package/capture-params.js +42 -0
  153. package/server/dist/model-package/pack.d.ts +23 -0
  154. package/server/dist/model-package/pack.js +230 -0
  155. package/server/dist/model-package/types.d.ts +79 -0
  156. package/server/dist/model-package/types.js +17 -0
  157. package/server/dist/routes/hit-test.d.ts +3 -0
  158. package/server/dist/routes/hit-test.js +17 -0
  159. package/server/dist/routes/pack.d.ts +10 -0
  160. package/server/dist/routes/pack.js +47 -0
  161. package/server/dist/routes/params.d.ts +3 -0
  162. package/server/dist/routes/params.js +75 -0
  163. package/server/dist/routes/sketch-edits.d.ts +3 -0
  164. package/server/dist/routes/sketch-edits.js +542 -0
  165. package/server/dist/routes/timeline.d.ts +3 -0
  166. package/server/dist/routes/timeline.js +49 -0
  167. package/server/dist/server-core.d.ts +53 -0
  168. package/server/dist/server-core.js +147 -0
  169. package/server/dist/ws-protocol.d.ts +101 -2
  170. package/ui/dist/assets/index-CDJmUpFI.css +2 -0
  171. package/ui/dist/assets/index-MRqwG9Vh.js +5417 -0
  172. package/ui/dist/index.html +2 -2
  173. package/server/dist/routes/actions.d.ts +0 -3
  174. package/server/dist/routes/actions.js +0 -309
  175. package/ui/dist/assets/index-BdqrMDRu.js +0 -4946
  176. package/ui/dist/assets/index-DR7c2Qk9.css +0 -2
@@ -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;
@@ -1,6 +1,7 @@
1
1
  import { Shell } from "../features/shell.js";
2
2
  import { SceneObject } from "../common/scene-object.js";
3
3
  import { registerBuilder } from "../index.js";
4
+ import { isNumberParam, resolveParam } from "./param.js";
4
5
  function build(context) {
5
6
  return function shell() {
6
7
  const args = Array.from(arguments);
@@ -14,8 +15,8 @@ function build(context) {
14
15
  selections.push(implicit);
15
16
  }
16
17
  }
17
- const thickness = (args.length >= 1 && typeof args[0] === 'number')
18
- ? args[0]
18
+ const thickness = (args.length >= 1 && isNumberParam(args[0]))
19
+ ? resolveParam(args[0])
19
20
  : 2.5;
20
21
  for (const sel of selections) {
21
22
  context.addSceneObject(sel);
@@ -1,16 +1,17 @@
1
1
  import { ITransformable } from "./interfaces.js";
2
+ import { type NumberParam } from "./param.js";
2
3
  interface SphereFunction {
3
4
  /**
4
5
  * Creates a full sphere with the given radius.
5
6
  * @param radius - The sphere radius
6
7
  */
7
- (radius: number): ITransformable;
8
+ (radius: NumberParam): ITransformable;
8
9
  /**
9
10
  * Creates a partial sphere with the given radius and sweep angle.
10
11
  * @param radius - The sphere radius
11
12
  * @param angle - The sweep angle in degrees
12
13
  */
13
- (radius: number, angle: number): ITransformable;
14
+ (radius: NumberParam, angle: NumberParam): ITransformable;
14
15
  }
15
16
  declare const _default: SphereFunction;
16
17
  export default _default;
@@ -1,9 +1,10 @@
1
1
  import { Sphere } from "../features/sphere.js";
2
2
  import { rad } from "../helpers/math-helpers.js";
3
3
  import { registerBuilder } from "../index.js";
4
+ import { resolveParam } from "./param.js";
4
5
  function build(context) {
5
6
  return function sphere(radius, angle = 360) {
6
- const sphere = new Sphere(radius, rad(angle));
7
+ const sphere = new Sphere(resolveParam(radius), rad(resolveParam(angle)));
7
8
  context.addSceneObject(sphere);
8
9
  return sphere;
9
10
  };
@@ -1,26 +1,27 @@
1
1
  import { PointLike } from "../math/point.js";
2
2
  import { ISceneObject, ITranslate } from "./interfaces.js";
3
+ import { type NumberParam, type BooleanParam } from "./param.js";
3
4
  interface TranslateFunction {
4
5
  /**
5
6
  * Translates objects along the X axis.
6
7
  * @param x - The X distance
7
8
  * @param targets - The objects to translate (defaults to last object)
8
9
  */
9
- (x: number, ...targets: ISceneObject[]): ITranslate;
10
+ (x: NumberParam, ...targets: ISceneObject[]): ITranslate;
10
11
  /**
11
12
  * Translates objects along the X axis, optionally making a copy.
12
13
  * @param x - The X distance
13
14
  * @param copy - Whether to copy instead of move
14
15
  * @param targets - The objects to translate (defaults to last object)
15
16
  */
16
- (x: number, copy: boolean, ...targets: ISceneObject[]): ITranslate;
17
+ (x: NumberParam, copy: BooleanParam, ...targets: ISceneObject[]): ITranslate;
17
18
  /**
18
19
  * Translates objects along the X and Y axes.
19
20
  * @param x - The X distance
20
21
  * @param y - The Y distance
21
22
  * @param targets - The objects to translate (defaults to last object)
22
23
  */
23
- (x: number, y: number, ...targets: ISceneObject[]): ITranslate;
24
+ (x: NumberParam, y: NumberParam, ...targets: ISceneObject[]): ITranslate;
24
25
  /**
25
26
  * Translates objects along the X and Y axes, optionally making a copy.
26
27
  * @param x - The X distance
@@ -28,7 +29,7 @@ interface TranslateFunction {
28
29
  * @param copy - Whether to copy instead of move
29
30
  * @param targets - The objects to translate (defaults to last object)
30
31
  */
31
- (x: number, y: number, copy: boolean, ...targets: ISceneObject[]): ITranslate;
32
+ (x: NumberParam, y: NumberParam, copy: BooleanParam, ...targets: ISceneObject[]): ITranslate;
32
33
  /**
33
34
  * Translates objects along all three axes.
34
35
  * @param x - The X distance
@@ -36,7 +37,7 @@ interface TranslateFunction {
36
37
  * @param z - The Z distance
37
38
  * @param targets - The objects to translate (defaults to last object)
38
39
  */
39
- (x: number, y: number, z: number, ...targets: ISceneObject[]): ITranslate;
40
+ (x: NumberParam, y: NumberParam, z: NumberParam, ...targets: ISceneObject[]): ITranslate;
40
41
  /**
41
42
  * Translates objects along all three axes, optionally making a copy.
42
43
  * @param x - The X distance
@@ -45,7 +46,7 @@ interface TranslateFunction {
45
46
  * @param copy - Whether to copy instead of move
46
47
  * @param targets - The objects to translate (defaults to last object)
47
48
  */
48
- (x: number, y: number, z: number, copy: boolean, ...targets: ISceneObject[]): ITranslate;
49
+ (x: NumberParam, y: NumberParam, z: NumberParam, copy: BooleanParam, ...targets: ISceneObject[]): ITranslate;
49
50
  /**
50
51
  * Translates objects by a point-like offset.
51
52
  * @param distance - The offset as a point
@@ -5,6 +5,7 @@ import { Point } from "../math/point.js";
5
5
  import { SceneObject } from "../common/scene-object.js";
6
6
  import { Vertex } from "../common/vertex.js";
7
7
  import { LazyVertex } from "../features/lazy-vertex.js";
8
+ import { isNumberParam, isBooleanParam, resolveParam } from "./param.js";
8
9
  function build(context) {
9
10
  return function translate() {
10
11
  const args = Array.from(arguments);
@@ -14,12 +15,12 @@ function build(context) {
14
15
  targets.unshift(args.pop());
15
16
  }
16
17
  // Extract copy flag from the end (if boolean)
17
- const copy = typeof args[args.length - 1] === 'boolean' ? args.pop() : false;
18
+ const copy = isBooleanParam(args[args.length - 1]) ? resolveParam(args.pop()) : false;
18
19
  // translate(x, y?, z?)
19
- if (typeof args[0] === 'number') {
20
- const x = args[0];
21
- const y = args[1] ?? 0;
22
- const z = args[2] ?? 0;
20
+ if (isNumberParam(args[0])) {
21
+ const x = resolveParam(args[0]);
22
+ const y = isNumberParam(args[1]) ? resolveParam(args[1]) : 0;
23
+ const z = isNumberParam(args[2]) ? resolveParam(args[2]) : 0;
23
24
  const vertex = Vertex.fromPoint(new Point(x, y, z));
24
25
  const lazyVertex = LazyVertex.fromVertex(vertex);
25
26
  const translate = new Translate(lazyVertex, copy, ...targets);
@@ -115,7 +115,7 @@ export class Arc extends GeometrySceneObject {
115
115
  this.setTangent(new Point2D(tx, ty));
116
116
  this.setState('start', Vertex.fromPoint2D(startPt));
117
117
  this.setState('end', Vertex.fromPoint2D(endPt));
118
- const centerVertex = Vertex.fromPoint2D(centerPt);
118
+ const centerVertex = Vertex.fromPoint(center);
119
119
  centerVertex.markAsMetaShape();
120
120
  this.addShape(centerVertex);
121
121
  this.addShape(edge);
@@ -161,7 +161,7 @@ export class Arc extends GeometrySceneObject {
161
161
  this.setTangent(new Point2D(endTx, endTy));
162
162
  this.setState('start', Vertex.fromPoint2D(startPoint));
163
163
  this.setState('end', Vertex.fromPoint2D(targetPoint));
164
- const centerVertex = Vertex.fromPoint2D(centerPoint);
164
+ const centerVertex = Vertex.fromPoint(center);
165
165
  centerVertex.markAsMetaShape();
166
166
  this.addShape(centerVertex);
167
167
  this.addShape(edge);
@@ -209,7 +209,7 @@ export class Arc extends GeometrySceneObject {
209
209
  this.setTangent(new Point2D(endTx, endTy));
210
210
  this.setState('start', Vertex.fromPoint2D(startPoint));
211
211
  this.setState('end', Vertex.fromPoint2D(targetPoint));
212
- const centerVertex = Vertex.fromPoint2D(centerPoint);
212
+ const centerVertex = Vertex.fromPoint(center);
213
213
  centerVertex.markAsMetaShape();
214
214
  this.addShape(centerVertex);
215
215
  this.addShape(edge);
@@ -269,7 +269,7 @@ export class Arc extends GeometrySceneObject {
269
269
  this.setTangent(new Point2D(tx, ty));
270
270
  this.setState('start', Vertex.fromPoint2D(startPt));
271
271
  this.setState('end', Vertex.fromPoint2D(endPt));
272
- const centerVertex = Vertex.fromPoint2D(actualCenter);
272
+ const centerVertex = Vertex.fromPoint(plane.localToWorld(actualCenter));
273
273
  centerVertex.markAsMetaShape();
274
274
  this.addShape(centerVertex);
275
275
  this.addShape(edge);
@@ -317,7 +317,7 @@ export class Arc extends GeometrySceneObject {
317
317
  const edge = Geometry.makeEdgeFromCurve(arc);
318
318
  this.setState('start', Vertex.fromPoint2D(startPoint));
319
319
  this.setState('end', Vertex.fromPoint2D(endPoint));
320
- const centerVertex = Vertex.fromPoint2D(centerPoint);
320
+ const centerVertex = Vertex.fromPoint(center);
321
321
  centerVertex.markAsMetaShape();
322
322
  this.addShape(centerVertex);
323
323
  const sign = cw ? -1 : 1;
@@ -11,16 +11,20 @@ export class BezierCurve extends GeometrySceneObject {
11
11
  this.controlPoints = controlPoints;
12
12
  }
13
13
  build() {
14
- if (this.controlPoints.length === 0) {
14
+ const points = this.controlPoints.map(cp => cp.asPoint2D());
15
+ if (points.length < 2) {
16
+ // 0 args: interactive placeholder. 1 arg: start placed, no curve yet.
17
+ if (points.length === 1) {
18
+ this.setState('start', Vertex.fromPoint2D(points[0]));
19
+ this.setCurrentPosition(points[0]);
20
+ }
15
21
  return;
16
22
  }
17
23
  const plane = this.sketch.getPlane();
18
- const currentPos = this.getCurrentPosition();
19
- const points = this.controlPoints.map(cp => cp.asPoint2D());
20
- // Poles: [currentPos (start), ...controlPoints, endPoint]
21
- // All args are in order: control points then endpoint (last arg)
22
- const poles2D = [currentPos, ...points];
23
- const polesWorld = poles2D.map(p => plane.localToWorld(p));
24
+ const startPoint = points[0];
25
+ const endPoint = points[points.length - 1];
26
+ // Poles: all args in order — first is start, last is endpoint, middle are controls.
27
+ const polesWorld = points.map(p => plane.localToWorld(p));
24
28
  const bezierCurve = Geometry.makeBezierCurve(polesWorld);
25
29
  // Compute tangent at endpoint before creating the edge
26
30
  const oc = getOC();
@@ -29,11 +33,9 @@ export class BezierCurve extends GeometrySceneObject {
29
33
  bezierCurve.D1(bezierCurve.LastParameter(), gpP, gpV);
30
34
  const tangentWorld = Convert.toVector3d(gpV, true);
31
35
  gpP.delete();
32
- // Project tangent to 2D sketch coordinates
33
36
  const tangent2D = new Point2D(tangentWorld.dot(plane.xDirection), tangentWorld.dot(plane.yDirection)).normalize();
34
37
  const edge = Geometry.makeEdgeFromBezier(bezierCurve);
35
- const endPoint = points[points.length - 1];
36
- this.setState('start', Vertex.fromPoint2D(currentPos));
38
+ this.setState('start', Vertex.fromPoint2D(startPoint));
37
39
  this.setState('end', Vertex.fromPoint2D(endPoint));
38
40
  this.addShape(edge);
39
41
  this.setTangent(tangent2D);
@@ -63,14 +65,12 @@ export class BezierCurve extends GeometrySceneObject {
63
65
  return `bezier-${this.controlPoints.length}`;
64
66
  }
65
67
  serialize() {
66
- const startPos = this.getCurrentPosition();
67
- const resolved = this.controlPoints.map(cp => {
68
- const p = cp.asPoint2D();
69
- return [p.x, p.y];
70
- });
68
+ const points = this.controlPoints.map(cp => cp.asPoint2D());
69
+ const start = points[0];
70
+ const resolved = points.slice(1).map(p => [p.x, p.y]);
71
71
  return {
72
72
  controlPoints: this.controlPoints,
73
- startPoint: [startPos.x, startPos.y],
73
+ startPoint: start ? [start.x, start.y] : null,
74
74
  resolvedPoints: resolved,
75
75
  };
76
76
  }
@@ -1,4 +1,5 @@
1
1
  import { Geometry } from "../../oc/geometry.js";
2
+ import { Vertex } from "../../common/vertex.js";
2
3
  import { ExtrudableGeometryBase } from "./extrudable-base.js";
3
4
  export class Circle extends ExtrudableGeometryBase {
4
5
  diameter;
@@ -21,6 +22,9 @@ export class Circle extends ExtrudableGeometryBase {
21
22
  const circle = Geometry.makeCircle(plane.localToWorld(center), radius, plane.normal);
22
23
  let edge = Geometry.makeEdgeFromCircle(circle);
23
24
  this.addShape(edge);
25
+ const centerVertex = Vertex.fromPoint2D(center);
26
+ centerVertex.markAsMetaShape();
27
+ this.addShape(centerVertex);
24
28
  if (this.sketch) {
25
29
  this.setCurrentPosition(center);
26
30
  }
@@ -1,4 +1,5 @@
1
1
  import { Geometry } from "../../oc/geometry.js";
2
+ import { Vertex } from "../../common/vertex.js";
2
3
  import { ExtrudableGeometryBase } from "./extrudable-base.js";
3
4
  export class Ellipse extends ExtrudableGeometryBase {
4
5
  rx;
@@ -29,6 +30,9 @@ export class Ellipse extends ExtrudableGeometryBase {
29
30
  const majorAxisDir = rxIsMajor ? plane.xDirection : plane.yDirection;
30
31
  const edge = Geometry.makeEllipseEdge(plane.localToWorld(center), major, minor, plane.normal, majorAxisDir);
31
32
  this.addShape(edge);
33
+ const centerVertex = Vertex.fromPoint2D(center);
34
+ centerVertex.markAsMetaShape();
35
+ this.addShape(centerVertex);
32
36
  if (this.sketch) {
33
37
  this.setCurrentPosition(center);
34
38
  }
@@ -6,8 +6,10 @@ export declare class HorizontalLine extends GeometrySceneObject implements IHLin
6
6
  distanceOrTarget: number | SceneObject;
7
7
  private targetPlane;
8
8
  private _centered;
9
+ private _hasExplicitStart;
9
10
  constructor(distanceOrTarget: number | SceneObject, targetPlane?: PlaneObjectBase);
10
11
  centered(value?: boolean): this;
12
+ setHasExplicitStart(value?: boolean): this;
11
13
  build(): void;
12
14
  getDependencies(): SceneObject[];
13
15
  createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
@@ -17,5 +19,6 @@ export declare class HorizontalLine extends GeometrySceneObject implements IHLin
17
19
  serialize(): {
18
20
  distance: number;
19
21
  centered: boolean;
22
+ hasExplicitStart: boolean;
20
23
  };
21
24
  }
@@ -8,6 +8,7 @@ export class HorizontalLine extends GeometrySceneObject {
8
8
  distanceOrTarget;
9
9
  targetPlane;
10
10
  _centered = false;
11
+ _hasExplicitStart = false;
11
12
  constructor(distanceOrTarget, targetPlane = null) {
12
13
  super();
13
14
  this.distanceOrTarget = distanceOrTarget;
@@ -17,6 +18,10 @@ export class HorizontalLine extends GeometrySceneObject {
17
18
  this._centered = value;
18
19
  return this;
19
20
  }
21
+ setHasExplicitStart(value = true) {
22
+ this._hasExplicitStart = value;
23
+ return this;
24
+ }
20
25
  build() {
21
26
  const plane = this.targetPlane?.getPlane() || this.sketch.getPlane();
22
27
  const currentPos = this.targetPlane
@@ -78,6 +83,7 @@ export class HorizontalLine extends GeometrySceneObject {
78
83
  : this.distanceOrTarget;
79
84
  const copy = new HorizontalLine(distanceOrTarget, targetPlane);
80
85
  copy.centered(this._centered);
86
+ copy._hasExplicitStart = this._hasExplicitStart;
81
87
  return copy;
82
88
  }
83
89
  compareTo(other) {
@@ -104,7 +110,7 @@ export class HorizontalLine extends GeometrySceneObject {
104
110
  else if (this.distanceOrTarget !== other.distanceOrTarget) {
105
111
  return false;
106
112
  }
107
- return this._centered === other._centered;
113
+ return this._centered === other._centered && this._hasExplicitStart === other._hasExplicitStart;
108
114
  }
109
115
  getType() {
110
116
  return 'line';
@@ -115,7 +121,8 @@ export class HorizontalLine extends GeometrySceneObject {
115
121
  serialize() {
116
122
  return {
117
123
  distance: typeof this.distanceOrTarget === 'number' ? this.distanceOrTarget : null,
118
- centered: this._centered
124
+ centered: this._centered,
125
+ hasExplicitStart: this._hasExplicitStart,
119
126
  };
120
127
  }
121
128
  }
@@ -5,7 +5,9 @@ import { GeometrySceneObject } from "./geometry.js";
5
5
  export declare class LineTo extends GeometrySceneObject {
6
6
  endPoint: LazyVertex;
7
7
  private targetPlane;
8
+ private _hasExplicitStart;
8
9
  constructor(endPoint: LazyVertex, targetPlane?: PlaneObjectBase);
10
+ setHasExplicitStart(value?: boolean): this;
9
11
  build(): void;
10
12
  createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
11
13
  compareTo(other: LineTo): boolean;
@@ -13,5 +15,6 @@ export declare class LineTo extends GeometrySceneObject {
13
15
  getUniqueType(): string;
14
16
  serialize(): {
15
17
  end: LazyVertex;
18
+ hasExplicitStart: boolean;
16
19
  };
17
20
  }
@@ -4,11 +4,16 @@ import { GeometrySceneObject } from "./geometry.js";
4
4
  export class LineTo extends GeometrySceneObject {
5
5
  endPoint;
6
6
  targetPlane;
7
+ _hasExplicitStart = false;
7
8
  constructor(endPoint, targetPlane = null) {
8
9
  super();
9
10
  this.endPoint = endPoint;
10
11
  this.targetPlane = targetPlane;
11
12
  }
13
+ setHasExplicitStart(value = true) {
14
+ this._hasExplicitStart = value;
15
+ return this;
16
+ }
12
17
  build() {
13
18
  const plane = this.targetPlane?.getPlane() || this.sketch.getPlane();
14
19
  const targetPoint = this.endPoint.asPoint2D();
@@ -32,7 +37,9 @@ export class LineTo extends GeometrySceneObject {
32
37
  }
33
38
  createCopy(remap) {
34
39
  const targetPlane = this.targetPlane ? (remap.get(this.targetPlane) || this.targetPlane) : null;
35
- return new LineTo(this.endPoint, targetPlane);
40
+ const copy = new LineTo(this.endPoint, targetPlane);
41
+ copy._hasExplicitStart = this._hasExplicitStart;
42
+ return copy;
36
43
  }
37
44
  compareTo(other) {
38
45
  if (!(other instanceof LineTo)) {
@@ -47,7 +54,7 @@ export class LineTo extends GeometrySceneObject {
47
54
  if (this.targetPlane && other.targetPlane && !this.targetPlane.compareTo(other.targetPlane)) {
48
55
  return false;
49
56
  }
50
- return this.endPoint.compareTo(other.endPoint);
57
+ return this.endPoint.compareTo(other.endPoint) && this._hasExplicitStart === other._hasExplicitStart;
51
58
  }
52
59
  getType() {
53
60
  return 'line';
@@ -57,7 +64,8 @@ export class LineTo extends GeometrySceneObject {
57
64
  }
58
65
  serialize() {
59
66
  return {
60
- end: this.endPoint
67
+ end: this.endPoint,
68
+ hasExplicitStart: this._hasExplicitStart,
61
69
  };
62
70
  }
63
71
  }
@@ -87,7 +87,11 @@ export class Sketch extends SceneObject {
87
87
  if (pos) {
88
88
  if (remaining === 0) {
89
89
  for (let j = i; j >= 0; j--) {
90
- const t = previous[j].getTangent();
90
+ const prev = previous[j];
91
+ if (!(prev instanceof GeometrySceneObject)) {
92
+ continue;
93
+ }
94
+ const t = prev.getTangent();
91
95
  if (t) {
92
96
  return { position: pos, tangent: t };
93
97
  }
@@ -1,13 +1,17 @@
1
1
  import { SceneObject } from "../../common/scene-object.js";
2
2
  import { PlaneObjectBase } from "../plane-renderable-base.js";
3
3
  import { ExtrudableGeometryBase } from "./extrudable-base.js";
4
+ import { LazyVertex } from "../lazy-vertex.js";
4
5
  import { ISlot } from "../../core/interfaces.js";
5
6
  export declare class Slot extends ExtrudableGeometryBase implements ISlot {
6
7
  distance: number;
7
8
  radius: number;
8
9
  private _center;
9
10
  private _angle;
11
+ private _startPoint;
12
+ private _endPoint;
10
13
  constructor(distance: number, radius: number, targetPlane?: PlaneObjectBase);
14
+ static fromTwoPoints(start: LazyVertex, end: LazyVertex, radius: number, targetPlane?: PlaneObjectBase | null): Slot;
11
15
  centered(value?: boolean): this;
12
16
  rotate(angle: number): this;
13
17
  build(): void;
@@ -20,5 +24,6 @@ export declare class Slot extends ExtrudableGeometryBase implements ISlot {
20
24
  radius: number;
21
25
  centered: boolean;
22
26
  angle: number;
27
+ hasTwoPoints: boolean;
23
28
  };
24
29
  }