fluidcad 0.0.33 → 0.0.34

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 (237) hide show
  1. package/README.md +3 -2
  2. package/bin/commands/init.js +55 -0
  3. package/bin/commands/mcp.js +33 -0
  4. package/bin/commands/serve.js +77 -0
  5. package/bin/fluidcad.js +15 -107
  6. package/lib/dist/common/scene-object.d.ts +2 -1
  7. package/lib/dist/common/scene-object.js +3 -2
  8. package/lib/dist/core/2d/tarc.d.ts +20 -2
  9. package/lib/dist/core/2d/tarc.js +24 -0
  10. package/lib/dist/core/interfaces.d.ts +31 -2
  11. package/lib/dist/core/repeat.js +62 -46
  12. package/lib/dist/features/2d/arc.d.ts +8 -2
  13. package/lib/dist/features/2d/arc.js +94 -17
  14. package/lib/dist/features/2d/back.js +3 -2
  15. package/lib/dist/features/2d/sketch.d.ts +4 -0
  16. package/lib/dist/features/2d/sketch.js +21 -0
  17. package/lib/dist/features/2d/tarc-constrained.d.ts +2 -0
  18. package/lib/dist/features/2d/tarc-constrained.js +8 -0
  19. package/lib/dist/features/2d/tarc-radius-to-object.d.ts +16 -0
  20. package/lib/dist/features/2d/tarc-radius-to-object.js +58 -0
  21. package/lib/dist/features/2d/tarc-to-object.d.ts +18 -0
  22. package/lib/dist/features/2d/tarc-to-object.js +66 -0
  23. package/lib/dist/features/2d/tarc-to-point-tangent.d.ts +2 -0
  24. package/lib/dist/features/2d/tarc-to-point-tangent.js +3 -0
  25. package/lib/dist/features/2d/tarc-to-point.d.ts +2 -0
  26. package/lib/dist/features/2d/tarc-to-point.js +3 -0
  27. package/lib/dist/features/2d/tarc-with-tangent.d.ts +2 -0
  28. package/lib/dist/features/2d/tarc-with-tangent.js +3 -0
  29. package/lib/dist/features/2d/tarc.d.ts +2 -0
  30. package/lib/dist/features/2d/tarc.js +3 -0
  31. package/lib/dist/features/extrude-base.d.ts +9 -0
  32. package/lib/dist/features/extrude-base.js +22 -0
  33. package/lib/dist/features/extrude-to-face.js +1 -5
  34. package/lib/dist/features/extrude-two-distances.js +1 -2
  35. package/lib/dist/features/extrude.js +1 -2
  36. package/lib/dist/features/mirror-feature.d.ts +3 -2
  37. package/lib/dist/features/mirror-feature.js +1 -1
  38. package/lib/dist/features/repeat-circular.d.ts +3 -3
  39. package/lib/dist/features/repeat-circular.js +8 -1
  40. package/lib/dist/features/repeat-linear.d.ts +4 -2
  41. package/lib/dist/features/repeat-linear.js +10 -1
  42. package/lib/dist/features/repeat-matrix.d.ts +3 -1
  43. package/lib/dist/features/repeat-matrix.js +7 -2
  44. package/lib/dist/features/shell.d.ts +4 -1
  45. package/lib/dist/features/shell.js +14 -3
  46. package/lib/dist/helpers/clone-transform.d.ts +2 -1
  47. package/lib/dist/index.d.ts +7 -1
  48. package/lib/dist/index.js +3 -3
  49. package/lib/dist/math/lazy-matrix.d.ts +31 -0
  50. package/lib/dist/math/lazy-matrix.js +66 -0
  51. package/lib/dist/oc/constraints/constraint-solver-adaptor.d.ts +5 -0
  52. package/lib/dist/oc/constraints/constraint-solver-adaptor.js +16 -0
  53. package/lib/dist/oc/constraints/constraint-solver.d.ts +4 -0
  54. package/lib/dist/oc/constraints/curve/curve-constraint-solver.d.ts +4 -0
  55. package/lib/dist/oc/constraints/curve/curve-constraint-solver.js +3 -0
  56. package/lib/dist/oc/constraints/geometric/geometric-constraint-solver.d.ts +6 -1
  57. package/lib/dist/oc/constraints/geometric/geometric-constraint-solver.js +4 -0
  58. package/lib/dist/oc/constraints/geometric/tangent-arc-from-point-tangent.d.ts +8 -0
  59. package/lib/dist/oc/constraints/geometric/tangent-arc-from-point-tangent.js +111 -0
  60. package/lib/dist/oc/constraints/geometric/tangent-arc-radius-to-object.d.ts +8 -0
  61. package/lib/dist/oc/constraints/geometric/tangent-arc-radius-to-object.js +161 -0
  62. package/lib/dist/oc/mesh.d.ts +9 -4
  63. package/lib/dist/oc/mesh.js +14 -13
  64. package/lib/dist/oc/shell-ops.d.ts +2 -1
  65. package/lib/dist/oc/shell-ops.js +5 -2
  66. package/lib/dist/rendering/mesh-builder.d.ts +3 -0
  67. package/lib/dist/rendering/mesh-builder.js +8 -4
  68. package/lib/dist/rendering/render-edge.d.ts +2 -1
  69. package/lib/dist/rendering/render-edge.js +2 -2
  70. package/lib/dist/rendering/render-face.d.ts +2 -1
  71. package/lib/dist/rendering/render-face.js +2 -2
  72. package/lib/dist/rendering/render-solid.d.ts +2 -1
  73. package/lib/dist/rendering/render-solid.js +2 -2
  74. package/lib/dist/rendering/render-wire.d.ts +2 -1
  75. package/lib/dist/rendering/render-wire.js +2 -2
  76. package/lib/dist/rendering/render.d.ts +3 -0
  77. package/lib/dist/rendering/render.js +7 -2
  78. package/lib/dist/scene-manager.d.ts +4 -2
  79. package/lib/dist/scene-manager.js +12 -4
  80. package/lib/dist/tests/features/2d/arc.test.js +64 -0
  81. package/lib/dist/tests/features/2d/back.test.js +17 -1
  82. package/lib/dist/tests/features/2d/tarc.test.js +157 -0
  83. package/lib/dist/tests/features/repeat-user-repro.test.d.ts +1 -0
  84. package/lib/dist/tests/features/repeat-user-repro.test.js +60 -0
  85. package/lib/dist/tests/features/shell.test.js +36 -0
  86. package/lib/dist/tests/global-setup.js +2 -1
  87. package/lib/dist/tests/helpers/extract-blocks.d.ts +9 -0
  88. package/lib/dist/tests/helpers/extract-blocks.js +56 -0
  89. package/lib/dist/tests/llm-docs-examples.test.d.ts +1 -0
  90. package/lib/dist/tests/llm-docs-examples.test.js +62 -0
  91. package/lib/dist/tests/setup.js +2 -1
  92. package/lib/dist/tsconfig.tsbuildinfo +1 -1
  93. package/llm-docs/.coverage-allowlist.txt +9 -0
  94. package/llm-docs/api/arc.md +48 -0
  95. package/llm-docs/api/axis.md +42 -0
  96. package/llm-docs/api/bezier.md +42 -0
  97. package/llm-docs/api/booleans.md +44 -0
  98. package/llm-docs/api/chamfer.md +40 -0
  99. package/llm-docs/api/circle.md +36 -0
  100. package/llm-docs/api/color.md +34 -0
  101. package/llm-docs/api/connect.md +41 -0
  102. package/llm-docs/api/constraint-qualifiers.md +48 -0
  103. package/llm-docs/api/copy.md +63 -0
  104. package/llm-docs/api/cursor-lines.md +50 -0
  105. package/llm-docs/api/cursor-move.md +61 -0
  106. package/llm-docs/api/cut.md +55 -0
  107. package/llm-docs/api/draft.md +36 -0
  108. package/llm-docs/api/edge-filter.md +57 -0
  109. package/llm-docs/api/ellipse.md +34 -0
  110. package/llm-docs/api/extrude.md +74 -0
  111. package/llm-docs/api/face-filter.md +61 -0
  112. package/llm-docs/api/fillet.md +51 -0
  113. package/llm-docs/api/index.json +139 -0
  114. package/llm-docs/api/line.md +42 -0
  115. package/llm-docs/api/load.md +37 -0
  116. package/llm-docs/api/local.md +38 -0
  117. package/llm-docs/api/loft.md +37 -0
  118. package/llm-docs/api/mirror.md +44 -0
  119. package/llm-docs/api/offset.md +36 -0
  120. package/llm-docs/api/part.md +40 -0
  121. package/llm-docs/api/plane.md +44 -0
  122. package/llm-docs/api/polygon.md +37 -0
  123. package/llm-docs/api/primitive-solids.md +39 -0
  124. package/llm-docs/api/project-intersect.md +48 -0
  125. package/llm-docs/api/rect.md +48 -0
  126. package/llm-docs/api/remove.md +32 -0
  127. package/llm-docs/api/repeat.md +79 -0
  128. package/llm-docs/api/revolve.md +38 -0
  129. package/llm-docs/api/rib.md +40 -0
  130. package/llm-docs/api/rotate.md +37 -0
  131. package/llm-docs/api/select.md +41 -0
  132. package/llm-docs/api/shell.md +41 -0
  133. package/llm-docs/api/sketch.md +76 -0
  134. package/llm-docs/api/slot.md +36 -0
  135. package/llm-docs/api/split-trim.md +42 -0
  136. package/llm-docs/api/sweep.md +43 -0
  137. package/llm-docs/api/tarc.md +45 -0
  138. package/llm-docs/api/tcircle.md +38 -0
  139. package/llm-docs/api/tline.md +42 -0
  140. package/llm-docs/api/translate.md +40 -0
  141. package/llm-docs/api/types/aline.md +35 -0
  142. package/llm-docs/api/types/arc-angles.md +29 -0
  143. package/llm-docs/api/types/arc-points.md +48 -0
  144. package/llm-docs/api/types/axis-like.md +38 -0
  145. package/llm-docs/api/types/axis.md +21 -0
  146. package/llm-docs/api/types/boolean-operation.md +50 -0
  147. package/llm-docs/api/types/circular-repeat-options.md +31 -0
  148. package/llm-docs/api/types/common.md +32 -0
  149. package/llm-docs/api/types/cut.md +125 -0
  150. package/llm-docs/api/types/draft.md +21 -0
  151. package/llm-docs/api/types/extrudable-geometry.md +23 -0
  152. package/llm-docs/api/types/extrude.md +194 -0
  153. package/llm-docs/api/types/geometry.md +51 -0
  154. package/llm-docs/api/types/hline.md +35 -0
  155. package/llm-docs/api/types/linear-repeat-options.md +31 -0
  156. package/llm-docs/api/types/loft.md +154 -0
  157. package/llm-docs/api/types/mirror.md +35 -0
  158. package/llm-docs/api/types/offset.md +31 -0
  159. package/llm-docs/api/types/plane-like.md +35 -0
  160. package/llm-docs/api/types/plane-transform-options.md +29 -0
  161. package/llm-docs/api/types/plane.md +21 -0
  162. package/llm-docs/api/types/point-like.md +22 -0
  163. package/llm-docs/api/types/point2dlike.md +26 -0
  164. package/llm-docs/api/types/polygon.md +46 -0
  165. package/llm-docs/api/types/rect.md +128 -0
  166. package/llm-docs/api/types/revolve.md +102 -0
  167. package/llm-docs/api/types/rib.md +133 -0
  168. package/llm-docs/api/types/scene-object.md +33 -0
  169. package/llm-docs/api/types/select.md +21 -0
  170. package/llm-docs/api/types/shell.md +54 -0
  171. package/llm-docs/api/types/slot.md +43 -0
  172. package/llm-docs/api/types/sweep.md +189 -0
  173. package/llm-docs/api/types/tangent-arc-two-objects.md +46 -0
  174. package/llm-docs/api/types/transformable.md +93 -0
  175. package/llm-docs/api/types/trim.md +27 -0
  176. package/llm-docs/api/types/two-objects-tangent-line.md +46 -0
  177. package/llm-docs/api/types/vertex.md +17 -0
  178. package/llm-docs/api/types/vline.md +35 -0
  179. package/llm-docs/concepts/coordinate-system.md +45 -0
  180. package/llm-docs/concepts/history-and-rollback.md +40 -0
  181. package/llm-docs/concepts/last-selection.md +49 -0
  182. package/llm-docs/concepts/scene-graph.md +37 -0
  183. package/llm-docs/index.json +1750 -0
  184. package/mcp/dist/client.d.ts +64 -0
  185. package/mcp/dist/client.js +248 -0
  186. package/mcp/dist/discovery.d.ts +11 -0
  187. package/mcp/dist/discovery.js +78 -0
  188. package/mcp/dist/docs-index.d.ts +81 -0
  189. package/mcp/dist/docs-index.js +261 -0
  190. package/mcp/dist/resources.d.ts +4 -0
  191. package/mcp/dist/resources.js +115 -0
  192. package/mcp/dist/server.d.ts +12 -0
  193. package/mcp/dist/server.js +489 -0
  194. package/mcp/dist/tools/coordination.d.ts +9 -0
  195. package/mcp/dist/tools/coordination.js +46 -0
  196. package/mcp/dist/tools/docs.d.ts +66 -0
  197. package/mcp/dist/tools/docs.js +122 -0
  198. package/mcp/dist/tools/engine.d.ts +56 -0
  199. package/mcp/dist/tools/engine.js +145 -0
  200. package/mcp/dist/tools/inspection.d.ts +75 -0
  201. package/mcp/dist/tools/inspection.js +121 -0
  202. package/mcp/dist/tools/screenshot.d.ts +63 -0
  203. package/mcp/dist/tools/screenshot.js +263 -0
  204. package/mcp/dist/tools/source.d.ts +84 -0
  205. package/mcp/dist/tools/source.js +434 -0
  206. package/mcp/dist/tools/workspaces.d.ts +13 -0
  207. package/mcp/dist/tools/workspaces.js +33 -0
  208. package/mcp/dist/types.d.ts +18 -0
  209. package/mcp/dist/types.js +11 -0
  210. package/package.json +19 -5
  211. package/server/dist/code-editor.d.ts +36 -0
  212. package/server/dist/code-editor.js +8 -0
  213. package/server/dist/fluidcad-server.d.ts +50 -0
  214. package/server/dist/fluidcad-server.js +153 -1
  215. package/server/dist/global-registry.d.ts +30 -0
  216. package/server/dist/global-registry.js +126 -0
  217. package/server/dist/index.js +171 -26
  218. package/server/dist/instance-file.d.ts +31 -0
  219. package/server/dist/instance-file.js +73 -0
  220. package/server/dist/lint-fluid-js.d.ts +15 -0
  221. package/server/dist/lint-fluid-js.js +271 -0
  222. package/server/dist/routes/editor.d.ts +24 -0
  223. package/server/dist/routes/editor.js +44 -0
  224. package/server/dist/routes/export.d.ts +1 -1
  225. package/server/dist/routes/export.js +45 -8
  226. package/server/dist/routes/health.d.ts +7 -0
  227. package/server/dist/routes/health.js +14 -0
  228. package/server/dist/routes/lint.d.ts +10 -0
  229. package/server/dist/routes/lint.js +28 -0
  230. package/server/dist/routes/render.d.ts +33 -0
  231. package/server/dist/routes/render.js +34 -0
  232. package/server/dist/routes/scene.d.ts +5 -0
  233. package/server/dist/routes/scene.js +48 -0
  234. package/server/dist/routes/screenshot.js +68 -1
  235. package/server/dist/ws-protocol.d.ts +56 -2
  236. package/ui/dist/assets/{index-CFi9p7wR.js → index-BdqrMDRu.js} +21 -21
  237. package/ui/dist/index.html +1 -1
package/README.md CHANGED
@@ -216,10 +216,10 @@ See the full list of commands in the [Neovim plugin README](extension/neovim/REA
216
216
  <details>
217
217
  <summary><strong>Any Other Editor</strong></summary>
218
218
 
219
- Run the FluidCAD server directly:
219
+ From your project directory, run the FluidCAD server directly:
220
220
 
221
221
  ```bash
222
- npx fluidcad -w ./my-app
222
+ npx fluidcad serve
223
223
  ```
224
224
 
225
225
  This starts a local server and opens a 3D viewport in your browser. Edit your `.fluid.js` files in any editor -- the viewport updates on save.
@@ -230,6 +230,7 @@ This starts a local server and opens a 3D viewport in your browser. Edit your `.
230
230
  |------|-------------|---------|
231
231
  | `-w, --workspace <path>` | Path to your project | Current directory |
232
232
  | `-p, --port <port>` | Server port | `3100` |
233
+ | `--open` | Open the viewport in your default browser when ready | _off_ |
233
234
 
234
235
  </details>
235
236
 
@@ -0,0 +1,55 @@
1
+ import { writeFileSync, existsSync } from 'fs';
2
+ import { resolve } from 'path';
3
+
4
+ const INIT_JS = `import { init } from 'fluidcad'\n\nexport default await init()\n`;
5
+
6
+ const TEST_FLUID_JS = `import { extrude, fillet, rect, shell, sketch } from "fluidcad/core";
7
+
8
+ sketch("xy", () => {
9
+ rect(100, 50).radius(10).centered();
10
+ });
11
+
12
+ const e = extrude(30);
13
+
14
+ fillet(4, e.startEdges());
15
+
16
+ shell(-2, e.endFaces());
17
+ `;
18
+
19
+ const JSCONFIG = JSON.stringify({
20
+ compilerOptions: {
21
+ checkJs: true,
22
+ module: 'node20',
23
+ },
24
+ }, null, 2) + '\n';
25
+
26
+ function runInit() {
27
+ const cwd = process.cwd();
28
+
29
+ const initPath = resolve(cwd, 'init.js');
30
+ if (existsSync(initPath)) {
31
+ console.error('init.js already exists in this directory.');
32
+ process.exit(1);
33
+ }
34
+
35
+ writeFileSync(initPath, INIT_JS);
36
+
37
+ const testPath = resolve(cwd, 'test.fluid.js');
38
+ if (!existsSync(testPath)) {
39
+ writeFileSync(testPath, TEST_FLUID_JS);
40
+ }
41
+
42
+ const jsconfigPath = resolve(cwd, 'jsconfig.json');
43
+ if (!existsSync(jsconfigPath)) {
44
+ writeFileSync(jsconfigPath, JSCONFIG);
45
+ }
46
+
47
+ console.log('FluidCAD initialized.');
48
+ }
49
+
50
+ export function registerInitCommand(program) {
51
+ program
52
+ .command('init')
53
+ .description('Scaffold init.js, test.fluid.js, and jsconfig.json in the current directory')
54
+ .action(runInit);
55
+ }
@@ -0,0 +1,33 @@
1
+ import { resolve, dirname } from 'path';
2
+ import { fileURLToPath } from 'url';
3
+
4
+ const __dirname = dirname(fileURLToPath(import.meta.url));
5
+ const mcpEntry = resolve(__dirname, '..', '..', 'mcp', 'dist', 'server.js');
6
+
7
+ async function runMcp() {
8
+ // stdout is reserved for the MCP protocol. Any incidental console.log from
9
+ // FluidCAD internals would corrupt the stream — route everything to stderr.
10
+ console.log = (...args) => console.error(...args);
11
+ console.info = (...args) => console.error(...args);
12
+
13
+ const mod = await import(mcpEntry);
14
+ if (typeof mod.runStdio !== 'function') {
15
+ console.error('mcp/dist/server.js does not export runStdio.');
16
+ process.exit(1);
17
+ }
18
+ await mod.runStdio();
19
+ }
20
+
21
+ export function registerMcpCommand(program) {
22
+ program
23
+ .command('mcp')
24
+ .description('Run the FluidCAD MCP server over stdio (for Claude Desktop, Claude Code, Cursor, ...)')
25
+ .action(async () => {
26
+ try {
27
+ await runMcp();
28
+ } catch (err) {
29
+ console.error(err?.stack || err?.message || String(err));
30
+ process.exit(1);
31
+ }
32
+ });
33
+ }
@@ -0,0 +1,77 @@
1
+ import { fork } from 'child_process';
2
+ import { resolve, dirname } from 'path';
3
+ import { fileURLToPath } from 'url';
4
+ import open from 'open';
5
+ import { createFileWatcher, findFluidFiles } from '../watcher.js';
6
+
7
+ const __dirname = dirname(fileURLToPath(import.meta.url));
8
+ const serverEntry = resolve(__dirname, '..', '..', 'server', 'dist', 'index.js');
9
+
10
+ function runServe(opts) {
11
+ const workspacePath = resolve(opts.workspace);
12
+ const port = String(opts.port);
13
+
14
+ const server = fork(serverEntry, [], {
15
+ env: {
16
+ ...process.env,
17
+ FLUIDCAD_SERVER_PORT: port,
18
+ FLUIDCAD_WORKSPACE_PATH: workspacePath,
19
+ },
20
+ stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
21
+ });
22
+
23
+ server.stdout.on('data', (data) => { process.stdout.write(data); });
24
+ server.stderr.on('data', (data) => { process.stderr.write(data); });
25
+
26
+ let watcher;
27
+
28
+ server.on('message', (msg) => {
29
+ if (msg.type === 'ready') {
30
+ console.log(`FluidCAD server ready at ${msg.url}`);
31
+ if (opts.open) {
32
+ open(msg.url).catch((err) => {
33
+ console.error(`Failed to open browser: ${err.message}`);
34
+ });
35
+ }
36
+ }
37
+ if (msg.type === 'init-complete') {
38
+ if (msg.success) {
39
+ console.log('FluidCAD initialized successfully.');
40
+ watcher = createFileWatcher(workspacePath, server);
41
+
42
+ const files = findFluidFiles(workspacePath);
43
+ if (files.length > 0) {
44
+ server.send({ type: 'process-file', filePath: files[0] });
45
+ }
46
+ } else {
47
+ console.error(`FluidCAD initialization failed: ${msg.error}`);
48
+ process.exit(1);
49
+ }
50
+ }
51
+ });
52
+
53
+ server.on('exit', (code) => {
54
+ if (watcher) { watcher.close(); }
55
+ process.exit(code || 0);
56
+ });
57
+
58
+ process.on('SIGINT', () => {
59
+ if (watcher) { watcher.close(); }
60
+ server.kill('SIGINT');
61
+ });
62
+
63
+ process.on('SIGTERM', () => {
64
+ if (watcher) { watcher.close(); }
65
+ server.kill('SIGTERM');
66
+ });
67
+ }
68
+
69
+ export function registerServeCommand(program) {
70
+ program
71
+ .command('serve')
72
+ .description('Start the FluidCAD server and watch .fluid.js files')
73
+ .option('-w, --workspace <path>', 'workspace directory', process.cwd())
74
+ .option('-p, --port <port>', 'server port', '3100')
75
+ .option('--open', 'open the UI in the default browser when ready', false)
76
+ .action(runServe);
77
+ }
package/bin/fluidcad.js CHANGED
@@ -1,115 +1,23 @@
1
1
  #!/usr/bin/env node
2
2
 
3
- import { fork } from 'child_process';
4
- import { resolve, dirname } from 'path';
3
+ import { Command } from 'commander';
4
+ import { readFileSync } from 'fs';
5
+ import { dirname, resolve } from 'path';
5
6
  import { fileURLToPath } from 'url';
6
- import { parseArgs } from 'util';
7
- import { writeFileSync, existsSync } from 'fs';
8
- import { createFileWatcher, findFluidFiles } from './watcher.js';
7
+ import { registerInitCommand } from './commands/init.js';
8
+ import { registerServeCommand } from './commands/serve.js';
9
+ import { registerMcpCommand } from './commands/mcp.js';
9
10
 
10
11
  const __dirname = dirname(fileURLToPath(import.meta.url));
12
+ const pkg = JSON.parse(readFileSync(resolve(__dirname, '..', 'package.json'), 'utf8'));
11
13
 
12
- const { values, positionals } = parseArgs({
13
- options: {
14
- port: { type: 'string', short: 'p', default: '3100' },
15
- workspace: { type: 'string', short: 'w', default: process.cwd() },
16
- },
17
- allowPositionals: true,
18
- });
14
+ const program = new Command()
15
+ .name('fluidcad')
16
+ .description('FluidCAD CLI')
17
+ .version(pkg.version);
19
18
 
20
- if (positionals[0] === 'init') {
21
- const cwd = process.cwd();
19
+ registerInitCommand(program);
20
+ registerServeCommand(program);
21
+ registerMcpCommand(program);
22
22
 
23
- const initPath = resolve(cwd, 'init.js');
24
- if (existsSync(initPath)) {
25
- console.error('init.js already exists in this directory.');
26
- process.exit(1);
27
- }
28
-
29
- writeFileSync(initPath, `import { init } from 'fluidcad'\n\nexport default await init()\n`);
30
-
31
- const testPath = resolve(cwd, 'test.fluid.js');
32
- if (!existsSync(testPath)) {
33
- writeFileSync(testPath, `import { extrude, fillet, rect, shell, sketch } from "fluidcad/core";
34
-
35
- sketch("xy", () => {
36
- rect(100, 50).radius(10).centered();
37
- });
38
-
39
- const e = extrude(30);
40
-
41
- fillet(4, e.startEdges());
42
-
43
- shell(-2, e.endFaces());
44
- `);
45
- }
46
-
47
- const jsconfigPath = resolve(cwd, 'jsconfig.json');
48
- if (!existsSync(jsconfigPath)) {
49
- writeFileSync(jsconfigPath, JSON.stringify({
50
- compilerOptions: {
51
- checkJs: true,
52
- module: 'node20',
53
- },
54
- }, null, 2) + '\n');
55
- }
56
-
57
- console.log('FluidCAD initialized.');
58
- process.exit(0);
59
- }
60
-
61
- const serverEntry = resolve(__dirname, '..', 'server', 'dist', 'index.js');
62
-
63
- const server = fork(serverEntry, [], {
64
- env: {
65
- ...process.env,
66
- FLUIDCAD_SERVER_PORT: values.port,
67
- FLUIDCAD_WORKSPACE_PATH: resolve(values.workspace),
68
- },
69
- stdio: ['pipe', 'pipe', 'pipe', 'ipc'],
70
- });
71
-
72
- server.stdout.on('data', (data) => {
73
- process.stdout.write(data);
74
- });
75
-
76
- server.stderr.on('data', (data) => {
77
- process.stderr.write(data);
78
- });
79
-
80
- const workspacePath = resolve(values.workspace);
81
- let watcher;
82
-
83
- server.on('message', (msg) => {
84
- if (msg.type === 'ready') {
85
- console.log(`FluidCAD server ready at ${msg.url}`);
86
- }
87
- if (msg.type === 'init-complete') {
88
- if (msg.success) {
89
- console.log('FluidCAD initialized successfully.');
90
- watcher = createFileWatcher(workspacePath, server);
91
-
92
- const files = findFluidFiles(workspacePath);
93
- if (files.length > 0) {
94
- server.send({ type: 'process-file', filePath: files[0] });
95
- }
96
- } else {
97
- console.error(`FluidCAD initialization failed: ${msg.error}`);
98
- process.exit(1);
99
- }
100
- }
101
- });
102
-
103
- server.on('exit', (code) => {
104
- process.exit(code || 0);
105
- });
106
-
107
- process.on('SIGINT', () => {
108
- if (watcher) { watcher.close(); }
109
- server.kill('SIGINT');
110
- });
111
-
112
- process.on('SIGTERM', () => {
113
- if (watcher) { watcher.close(); }
114
- server.kill('SIGTERM');
115
- });
23
+ program.parseAsync(process.argv);
@@ -2,6 +2,7 @@ import { Shape, ShapeFilter } from "./shape.js";
2
2
  import { Face } from "./face.js";
3
3
  import { Edge } from "./edge.js";
4
4
  import { Matrix4 } from "../math/matrix4.js";
5
+ import { LazyMatrix } from "../math/lazy-matrix.js";
5
6
  import { ISceneObject } from "../core/interfaces.js";
6
7
  import { FusionScope, OperationMode } from "../features/extrude-options.js";
7
8
  import { ShapeType } from "./shape-type.js";
@@ -90,7 +91,7 @@ export declare abstract class SceneObject implements Comparable<SceneObject>, Se
90
91
  getDependencies(): SceneObject[];
91
92
  createCopy(remap: Map<SceneObject, SceneObject>): SceneObject;
92
93
  clone(): SceneObject[];
93
- setTransform(matrix: Matrix4): void;
94
+ setTransform(matrix: Matrix4 | LazyMatrix): void;
94
95
  getTransform(): Matrix4 | null;
95
96
  setCloneSource(source: SceneObject): void;
96
97
  getCloneSource(): SceneObject | null;
@@ -1,4 +1,5 @@
1
1
  import { randomUUID } from "crypto";
2
+ import { LazyMatrix } from "../math/lazy-matrix.js";
2
3
  export class SceneObject {
3
4
  state;
4
5
  children = [];
@@ -200,10 +201,10 @@ export class SceneObject {
200
201
  return result;
201
202
  }
202
203
  setTransform(matrix) {
203
- this._transform = matrix;
204
+ this._transform = matrix instanceof LazyMatrix ? matrix : LazyMatrix.of(matrix);
204
205
  }
205
206
  getTransform() {
206
- return this._transform;
207
+ return this._transform ? this._transform.resolve() : null;
207
208
  }
208
209
  setCloneSource(source) {
209
210
  this._cloneSource = source;
@@ -1,7 +1,25 @@
1
1
  import { Point2DLike } from "../../math/point.js";
2
2
  import { QualifiedSceneObject } from "../../features/2d/constraints/qualified-geometry.js";
3
- import { IGeometry, ISceneObject, ITangentArcTwoObjects } from "../interfaces.js";
3
+ import { IGeometry, ISceneObject, ITangentArcToObject, ITangentArcTwoObjects } from "../interfaces.js";
4
4
  interface TArcFunction {
5
+ /**
6
+ * Draws a tangent arc from the current position using the current tangent
7
+ * direction, ending tangent to a target line. The radius is solved
8
+ * automatically; the arc must be tangent to the target but does not need
9
+ * to touch its finite extent. By default the arc curves to the left of
10
+ * the start tangent — chain `.flip()` to curve to the right instead.
11
+ * @param target - The target line (or a qualified line)
12
+ */
13
+ (target: ISceneObject | QualifiedSceneObject): ITangentArcToObject;
14
+ /**
15
+ * Draws a tangent arc from the current position using the current tangent
16
+ * direction, with the given radius, ending at the first intersection with
17
+ * the target geometry along the arc's sweep direction. A negative radius
18
+ * flips the sweep direction. Supported targets: lines, circles, and arcs.
19
+ * @param radius - The arc radius. A negative value flips the sweep direction.
20
+ * @param target - The target geometry to intersect with
21
+ */
22
+ (radius: number, target: ISceneObject | QualifiedSceneObject): IGeometry;
5
23
  /**
6
24
  * Draws a tangent arc with a given radius and end angle.
7
25
  * @param radius - The arc radius (defaults to 100). A negative value flips the sweep direction.
@@ -34,7 +52,7 @@ interface TArcFunction {
34
52
  */
35
53
  (startPoint: Point2DLike, endPoint: Point2DLike, tangent: Point2DLike): IGeometry;
36
54
  /**
37
- * Draws a tangent arc between two geometry objects.
55
+ * Draws all possible tangent arcs between two geometry objects.
38
56
  * @param c1 - The first geometry object
39
57
  * @param c2 - The second geometry object
40
58
  * @param radius - The arc radius
@@ -3,13 +3,37 @@ import { TangentArc } from "../../features/2d/tarc.js";
3
3
  import { TangentArcToPoint } from "../../features/2d/tarc-to-point.js";
4
4
  import { TangentArcToPointTangent } from "../../features/2d/tarc-to-point-tangent.js";
5
5
  import { TangentArcWithTangent } from "../../features/2d/tarc-with-tangent.js";
6
+ import { TangentArcToObject } from "../../features/2d/tarc-to-object.js";
7
+ import { TangentArcRadiusToObject } from "../../features/2d/tarc-radius-to-object.js";
6
8
  import { Move } from "../../features/2d/move.js";
7
9
  import { normalizePoint2D } from "../../helpers/normalize.js";
8
10
  import { registerBuilder } from "../../index.js";
9
11
  import { QualifiedSceneObject } from "../../features/2d/constraints/qualified-geometry.js";
10
12
  import { TangentArcTwoObjects } from "../../features/2d/tarc-constrained.js";
13
+ import { SceneObject } from "../../common/scene-object.js";
11
14
  function build(context) {
12
15
  return function tarc() {
16
+ // tArc(target): single scene-object target, radius solved automatically.
17
+ // LazyVertex extends SceneObject but represents a point — fall through to the
18
+ // Point2DLike branch below so tArc(lazyVertex) becomes tArc(endPoint).
19
+ if (arguments.length === 1 &&
20
+ ((arguments[0] instanceof SceneObject && !isPoint2DLike(arguments[0])) ||
21
+ arguments[0] instanceof QualifiedSceneObject)) {
22
+ const target = QualifiedSceneObject.from(arguments[0]);
23
+ const arc = new TangentArcToObject(target);
24
+ context.addSceneObject(arc);
25
+ return arc;
26
+ }
27
+ // tArc(radius, target): explicit radius, end at first intersection with target
28
+ if (arguments.length === 2 &&
29
+ typeof arguments[0] === 'number' &&
30
+ (arguments[1] instanceof SceneObject || arguments[1] instanceof QualifiedSceneObject)) {
31
+ const radius = arguments[0];
32
+ const target = QualifiedSceneObject.from(arguments[1]);
33
+ const arc = new TangentArcRadiusToObject(radius, target);
34
+ context.addSceneObject(arc);
35
+ return arc;
36
+ }
13
37
  // tarc(c1, c2, radius): fillet arc tangent to two circles/points
14
38
  if ((arguments.length === 3 || arguments.length === 4) && typeof arguments[2] === 'number') {
15
39
  const o1 = isPoint2DLike(arguments[0]) ? normalizePoint2D(arguments[0]) : arguments[0];
@@ -157,13 +157,27 @@ export interface IArcPoints extends IExtrudableGeometry {
157
157
  * Positive = CCW, negative = CW.
158
158
  * @param value - The bulge radius.
159
159
  */
160
- radius(value: number): this;
160
+ radius(value: number): IArcRadius;
161
161
  /**
162
162
  * Specifies the circle center point for the arc.
163
163
  * Mutually exclusive with `.radius()`.
164
164
  * @param value - The center point of the arc's circle.
165
165
  */
166
- center(value: Point2DLike): this;
166
+ center(value: Point2DLike): IArcCenter;
167
+ }
168
+ export interface IArcRadius extends IExtrudableGeometry {
169
+ /**
170
+ * Switches to the major arc (> 180°).
171
+ * By default, `.radius()` produces the minor arc (< 180°);
172
+ * `.major()` switches to the complementary major arc on the same circle.
173
+ */
174
+ major(): this;
175
+ }
176
+ export interface IArcCenter extends IExtrudableGeometry {
177
+ /**
178
+ * Sweeps the arc clockwise from start to end instead of the default counter-clockwise.
179
+ */
180
+ cw(): this;
167
181
  }
168
182
  export interface IArcAngles extends IExtrudableGeometry {
169
183
  /**
@@ -298,6 +312,14 @@ export interface ITwoObjectsTangentLine extends IGeometry {
298
312
  */
299
313
  end(index?: number): LazyVertex;
300
314
  }
315
+ export interface ITangentArcToObject extends IGeometry {
316
+ /**
317
+ * Flips the arc to the opposite side of the start tangent. By default,
318
+ * the arc curves to the left of the current tangent direction;
319
+ * `.flip()` switches it to the right.
320
+ */
321
+ flip(): this;
322
+ }
301
323
  export interface ITangentArcTwoObjects extends IGeometry {
302
324
  /**
303
325
  * Returns the start vertex of the tangent arc.
@@ -771,6 +793,7 @@ export interface IRib extends IBooleanOperation {
771
793
  */
772
794
  extend(): this;
773
795
  }
796
+ export type ShellJoinType = 'arc' | 'intersection' | 'tangent';
774
797
  export interface IShell extends ISceneObject {
775
798
  /**
776
799
  * Selects the inner wall faces created by the shell operation (from thickness removal).
@@ -783,4 +806,10 @@ export interface IShell extends ISceneObject {
783
806
  * @param args - Numeric indices or {@link EdgeFilterBuilder} instances to filter the selection.
784
807
  */
785
808
  internalEdges(...args: (number | EdgeFilterBuilder)[]): ISceneObject;
809
+ /**
810
+ * Sets the join type used at inner-wall corners.
811
+ * @param type - `'arc'` (default) for rounded blends, `'intersection'` for sharp corners,
812
+ * or `'tangent'` for tangent-continuous blends.
813
+ */
814
+ join(type: ShellJoinType): this;
786
815
  }