cyclecad 0.2.2 → 0.2.3

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 (69) hide show
  1. package/API-BUILD-MANIFEST.txt +339 -0
  2. package/API-SERVER.md +535 -0
  3. package/Architecture-Deck.pptx +0 -0
  4. package/CLAUDE.md +172 -11
  5. package/CLI-BUILD-SUMMARY.md +504 -0
  6. package/CLI-INDEX.md +356 -0
  7. package/CLI-README.md +466 -0
  8. package/COLLABORATION-INTEGRATION-GUIDE.md +325 -0
  9. package/CONNECTED_FABS_GUIDE.md +612 -0
  10. package/CONNECTED_FABS_README.md +310 -0
  11. package/DELIVERABLES.md +343 -0
  12. package/DFM-ANALYZER-INTEGRATION.md +368 -0
  13. package/DFM-QUICK-START.js +253 -0
  14. package/Dockerfile +69 -0
  15. package/IMPLEMENTATION.md +327 -0
  16. package/LICENSE +31 -0
  17. package/MARKETPLACE_QUICK_REFERENCE.txt +294 -0
  18. package/MCP-INDEX.md +264 -0
  19. package/QUICKSTART-API.md +388 -0
  20. package/QUICKSTART-CLI.md +211 -0
  21. package/QUICKSTART-MCP.md +196 -0
  22. package/README-MCP.md +208 -0
  23. package/TEST-TOKEN-ENGINE.md +319 -0
  24. package/TOKEN-ENGINE-SUMMARY.md +266 -0
  25. package/TOKENS-README.md +263 -0
  26. package/TOOLS-REFERENCE.md +254 -0
  27. package/app/index.html +168 -3
  28. package/app/js/TOKEN-INTEGRATION.md +391 -0
  29. package/app/js/agent-api.js +3 -3
  30. package/app/js/ai-copilot.js +1435 -0
  31. package/app/js/cam-pipeline.js +840 -0
  32. package/app/js/collaboration-ui.js +995 -0
  33. package/app/js/collaboration.js +1116 -0
  34. package/app/js/connected-fabs-example.js +404 -0
  35. package/app/js/connected-fabs.js +1449 -0
  36. package/app/js/dfm-analyzer.js +1760 -0
  37. package/app/js/marketplace.js +1994 -0
  38. package/app/js/material-library.js +2115 -0
  39. package/app/js/token-dashboard.js +563 -0
  40. package/app/js/token-engine.js +743 -0
  41. package/app/test-agent.html +1801 -0
  42. package/bin/cyclecad-cli.js +662 -0
  43. package/bin/cyclecad-mcp +2 -0
  44. package/bin/server.js +242 -0
  45. package/cycleCAD-Architecture.pptx +0 -0
  46. package/cycleCAD-Investor-Deck.pptx +0 -0
  47. package/demo-mcp.sh +60 -0
  48. package/docs/API-SERVER-SUMMARY.md +375 -0
  49. package/docs/API-SERVER.md +667 -0
  50. package/docs/CAM-EXAMPLES.md +344 -0
  51. package/docs/CAM-INTEGRATION.md +612 -0
  52. package/docs/CAM-QUICK-REFERENCE.md +199 -0
  53. package/docs/CLI-INTEGRATION.md +510 -0
  54. package/docs/CLI.md +872 -0
  55. package/docs/MARKETPLACE-API-SCHEMA.json +564 -0
  56. package/docs/MARKETPLACE-INTEGRATION.md +467 -0
  57. package/docs/MARKETPLACE-SETUP.html +439 -0
  58. package/docs/MCP-SERVER.md +403 -0
  59. package/examples/api-client-example.js +488 -0
  60. package/examples/api-client-example.py +359 -0
  61. package/examples/batch-manufacturing.txt +28 -0
  62. package/examples/batch-simple.txt +26 -0
  63. package/model-marketplace.html +1273 -0
  64. package/package.json +14 -3
  65. package/server/api-server.js +1120 -0
  66. package/server/mcp-server.js +1161 -0
  67. package/test-api-server.js +432 -0
  68. package/test-mcp.js +198 -0
  69. package/~$cycleCAD-Investor-Deck.pptx +0 -0
@@ -0,0 +1,612 @@
1
+ # CAM Pipeline Integration Guide
2
+
3
+ ## Overview
4
+
5
+ The CAM Pipeline module (`app/js/cam-pipeline.js`) implements the complete manufacturing preparation workflow:
6
+
7
+ ```
8
+ Slice → Nest → Toolpath → G-code → Export
9
+ ```
10
+
11
+ Supported manufacturing processes:
12
+ - **FDM** (3D printing): Ender 3, Prusa MK4, Bambu X1
13
+ - **SLA** (resin printing): Elegoo Mars, Formlabs Form 3
14
+ - **CNC** (milling): Shapeoko, Nomad 3, Tormach PCNC
15
+ - **Laser** (cutting/engraving): K40, xTool, Glowforge
16
+ - **SLS** (powder bed): Sinterit Lisa
17
+
18
+ ## Module Size
19
+
20
+ - **840 lines** of ES6 JavaScript
21
+ - **30 KB** uncompressed
22
+ - **0 dependencies** (uses only Three.js which is already loaded)
23
+ - Full-featured: 11 APIs, 14 machine profiles, 10 tools, 14 materials
24
+
25
+ ## API Reference
26
+
27
+ ### window.cycleCAD.cam.slice(mesh, options)
28
+
29
+ Slice a 3D mesh into layers for 3D printing.
30
+
31
+ ```javascript
32
+ const result = window.cycleCAD.cam.slice(mesh, {
33
+ layerHeight: 0.2, // 0.08-0.4 mm
34
+ infill: 20, // 0-100%
35
+ shells: 2, // 1-5 outer shells
36
+ supportAngle: 45, // Support overhang angle
37
+ material: 'pla', // Material type
38
+ printer: 'ender3' // Machine profile
39
+ });
40
+
41
+ // Returns:
42
+ // {
43
+ // printer: "Creality Ender 3",
44
+ // totalLayers: 125,
45
+ // layerHeight: 0.2,
46
+ // infill: 20,
47
+ // shells: 2,
48
+ // layers: [{index, z, paths}],
49
+ // material: 'pla',
50
+ // materialWeightG: 45,
51
+ // materialCostEUR: 0.36,
52
+ // estimatedTimeMinutes: 360,
53
+ // estimatedTimeReadable: "6h 0m",
54
+ // buildVolume: {x: 220, y: 220, z: 250},
55
+ // fits: true,
56
+ // gcode: "G28\nM104 S...",
57
+ // gcodeLength: 2850
58
+ // }
59
+ ```
60
+
61
+ ### window.cycleCAD.cam.nest(parts, sheetSize, options)
62
+
63
+ Arrange 2D parts on a flat sheet for laser cutting or waterjet.
64
+
65
+ ```javascript
66
+ const result = window.cycleCAD.cam.nest(
67
+ [
68
+ {id: 'part_a', width: 100, height: 50, quantity: 3},
69
+ {id: 'part_b', width: 80, height: 120, quantity: 2}
70
+ ],
71
+ {width: 1000, height: 500},
72
+ {spacing: 2, rotation: 'auto'}
73
+ );
74
+
75
+ // Returns:
76
+ // {
77
+ // sheetSize: {width: 1000, height: 500},
78
+ // placements: [
79
+ // {partId: "part_a", x: 0, y: 0, width: 100, height: 50, rotation: 0},
80
+ // ...
81
+ // ],
82
+ // totalParts: 5,
83
+ // usedArea: 41000,
84
+ // utilizationPercent: 82,
85
+ // wastePercent: 18,
86
+ // nestingScore: "A",
87
+ // svg: "<svg>...</svg>"
88
+ // }
89
+ ```
90
+
91
+ ### window.cycleCAD.cam.toolpath(mesh, options)
92
+
93
+ Generate CNC cutting or milling paths.
94
+
95
+ ```javascript
96
+ const result = window.cycleCAD.cam.toolpath(mesh, {
97
+ tool: 't_6mm_flat', // Tool from library
98
+ strategy: 'contour', // 'contour' | 'pocket' | 'drilling'
99
+ depthPerPass: 5, // mm
100
+ feedRate: 600, // mm/min
101
+ spindle: 1000, // RPM
102
+ machine: 'shapeoko'
103
+ });
104
+
105
+ // Returns:
106
+ // {
107
+ // machine: "Shapeoko 5",
108
+ // tool: "6mm Flat End Mill",
109
+ // strategy: "contour",
110
+ // depthPerPass: 5,
111
+ // feedRate: 600,
112
+ // spindle: 1000,
113
+ // passes: 4,
114
+ // paths: [{type, z, length, feed}],
115
+ // totalLength: 1250,
116
+ // estimatedTimeMinutes: 45,
117
+ // fits: true,
118
+ // gcode: "G90\nG94\nM3...",
119
+ // gcodeLength: 1820
120
+ // }
121
+ ```
122
+
123
+ ### window.cycleCAD.cam.exportGcode(gcode, filename)
124
+
125
+ Download G-code to file.
126
+
127
+ ```javascript
128
+ window.cycleCAD.cam.exportGcode(result.gcode, 'part_001.gcode');
129
+ // Triggers download
130
+ ```
131
+
132
+ ### window.cycleCAD.cam.compareCosts(mesh, options)
133
+
134
+ Compare costs across all manufacturing processes.
135
+
136
+ ```javascript
137
+ const result = window.cycleCAD.cam.compareCosts(mesh, {material: 'pla'});
138
+
139
+ // Returns:
140
+ // {
141
+ // volumeCm3: 45.2,
142
+ // material: "pla",
143
+ // processes: [
144
+ // {
145
+ // rank: 1,
146
+ // process: "FDM 3D Print",
147
+ // materialCost: 0.36,
148
+ // machineCost: 0.90,
149
+ // setupCost: 0,
150
+ // totalCost: 1.26,
151
+ // timeMinutes: 360,
152
+ // pros: ["Low cost", ...],
153
+ // cons: ["Layer lines", ...]
154
+ // },
155
+ // {
156
+ // rank: 2,
157
+ // process: "Laser Cut (Acrylic)",
158
+ // totalCost: 7.45,
159
+ // ...
160
+ // },
161
+ // ...
162
+ // ]
163
+ // }
164
+ ```
165
+
166
+ ### window.cycleCAD.cam.estimate(mesh, options)
167
+
168
+ Get time and cost for a specific process.
169
+
170
+ ```javascript
171
+ const result = window.cycleCAD.cam.estimate(mesh, {
172
+ process: 'FDM', // 'FDM' | 'CNC' | 'SLA'
173
+ material: 'pla',
174
+ machine: 'ender3',
175
+ quantity: 1
176
+ });
177
+
178
+ // Returns:
179
+ // {
180
+ // process: "FDM 3D Printing",
181
+ // machine: "Creality Ender 3",
182
+ // volumeCm3: 45.2,
183
+ // material: "pla",
184
+ // materialWeight: 56.1,
185
+ // materialCost: 0.45,
186
+ // machineTime: 380,
187
+ // machineCost: 1.90,
188
+ // setupCost: 0,
189
+ // totalPerUnit: 2.35,
190
+ // totalBatch: 2.35,
191
+ // timeMinutesReadable: "6h 20m",
192
+ // currency: "EUR"
193
+ // }
194
+ ```
195
+
196
+ ### window.cycleCAD.cam.getMachines()
197
+
198
+ List all available machines.
199
+
200
+ ```javascript
201
+ const machines = window.cycleCAD.cam.getMachines();
202
+ // Returns:
203
+ // [
204
+ // {id: 'ender3', name: 'Creality Ender 3', type: 'FDM', buildVolume: {...}, ...},
205
+ // {id: 'prusa_mk4', ...},
206
+ // ...
207
+ // ]
208
+ ```
209
+
210
+ ### window.cycleCAD.cam.getTools()
211
+
212
+ List all CNC tools.
213
+
214
+ ```javascript
215
+ const tools = window.cycleCAD.cam.getTools();
216
+ // Returns:
217
+ // [
218
+ // {id: 't_2mm_flat', name: '2mm Flat End Mill', diameter: 2, ...},
219
+ // ...
220
+ // ]
221
+ ```
222
+
223
+ ### window.cycleCAD.cam.getMaterials()
224
+
225
+ List all materials with densities and costs.
226
+
227
+ ```javascript
228
+ const materials = window.cycleCAD.cam.getMaterials();
229
+ // Returns:
230
+ // {
231
+ // materials: [
232
+ // {name: 'pla', density: 1.24, costPerKg: 8.00},
233
+ // {name: 'steel', density: 7.85, costPerKg: 0.50},
234
+ // ...
235
+ // ]
236
+ // }
237
+ ```
238
+
239
+ ## Integration into app/index.html
240
+
241
+ ### 1. Import the module
242
+
243
+ Add to the `<head>` or at the top of the app script:
244
+
245
+ ```html
246
+ <script type="module">
247
+ import camAPI from './app/js/cam-pipeline.js';
248
+ // camAPI is now available, and window.cycleCAD.cam is set
249
+ </script>
250
+ ```
251
+
252
+ ### 2. Add CAM UI Panel (optional)
253
+
254
+ Create a new panel in the app with tabs for each operation:
255
+
256
+ ```html
257
+ <div id="cam-panel" class="panel" style="display:none;">
258
+ <div class="panel-header">
259
+ <h3>CAM Pipeline</h3>
260
+ <button class="close-btn" data-close-panel="cam-panel">×</button>
261
+ </div>
262
+ <div class="panel-tabs">
263
+ <button class="tab-btn active" onclick="switchCamTab('slice')">Slice</button>
264
+ <button class="tab-btn" onclick="switchCamTab('nest')">Nest</button>
265
+ <button class="tab-btn" onclick="switchCamTab('toolpath')">Toolpath</button>
266
+ <button class="tab-btn" onclick="switchCamTab('estimate')">Estimate</button>
267
+ </div>
268
+
269
+ <!-- Slice Tab -->
270
+ <div id="cam-slice-tab" class="cam-tab active" style="display:block;">
271
+ <label>Printer: <select id="cam-printer">
272
+ <option value="ender3">Creality Ender 3</option>
273
+ <option value="prusa_mk4">Prusa MK4</option>
274
+ <option value="bambu_x1">Bambu Lab X1</option>
275
+ </select></label>
276
+ <label>Layer Height (mm): <input type="number" id="cam-layer-height" value="0.2" min="0.08" max="0.4" step="0.05"/></label>
277
+ <label>Infill (%): <input type="number" id="cam-infill" value="20" min="0" max="100"/></label>
278
+ <label>Material: <select id="cam-material">
279
+ <option value="pla">PLA</option>
280
+ <option value="petg">PETG</option>
281
+ <option value="abs">ABS</option>
282
+ <option value="nylon">Nylon</option>
283
+ </select></label>
284
+ <button onclick="camSlice()">Slice & Generate G-code</button>
285
+ <div id="cam-slice-result"></div>
286
+ </div>
287
+
288
+ <!-- Nest Tab -->
289
+ <div id="cam-nest-tab" class="cam-tab" style="display:none;">
290
+ <label>Sheet Width (mm): <input type="number" id="cam-sheet-width" value="1000"/></label>
291
+ <label>Sheet Height (mm): <input type="number" id="cam-sheet-height" value="500"/></label>
292
+ <label>Spacing (mm): <input type="number" id="cam-spacing" value="2"/></label>
293
+ <button onclick="camNest()">Nest Parts</button>
294
+ <div id="cam-nest-result"></div>
295
+ </div>
296
+
297
+ <!-- Toolpath Tab -->
298
+ <div id="cam-toolpath-tab" class="cam-tab" style="display:none;">
299
+ <label>Machine: <select id="cam-machine">
300
+ <option value="shapeoko">Shapeoko 5</option>
301
+ <option value="nomad3">Nomad 3</option>
302
+ <option value="tormach_pcnc">Tormach PCNC</option>
303
+ </select></label>
304
+ <label>Tool: <select id="cam-tool">
305
+ <option value="t_6mm_flat">6mm Flat End Mill</option>
306
+ <option value="t_3mm_ball">3mm Ball End Mill</option>
307
+ <option value="t_10mm_flat">10mm Flat End Mill</option>
308
+ </select></label>
309
+ <label>Strategy: <select id="cam-strategy">
310
+ <option value="contour">Contour</option>
311
+ <option value="pocket">Pocket</option>
312
+ <option value="drilling">Drilling</option>
313
+ </select></label>
314
+ <label>Feed Rate (mm/min): <input type="number" id="cam-feed-rate" value="600"/></label>
315
+ <button onclick="camToolpath()">Generate Toolpath</button>
316
+ <div id="cam-toolpath-result"></div>
317
+ </div>
318
+
319
+ <!-- Estimate Tab -->
320
+ <div id="cam-estimate-tab" class="cam-tab" style="display:none;">
321
+ <label>Process: <select id="cam-process">
322
+ <option value="FDM">FDM</option>
323
+ <option value="CNC">CNC</option>
324
+ <option value="SLA">SLA</option>
325
+ </select></label>
326
+ <label>Quantity: <input type="number" id="cam-quantity" value="1"/></label>
327
+ <button onclick="camCompare()">Compare All Processes</button>
328
+ <button onclick="camEstimate()">Get Estimate</button>
329
+ <div id="cam-estimate-result"></div>
330
+ </div>
331
+ </div>
332
+
333
+ <style>
334
+ #cam-panel {
335
+ position: fixed;
336
+ right: 0;
337
+ bottom: 60px;
338
+ width: 350px;
339
+ max-height: 600px;
340
+ background: #fff;
341
+ border: 1px solid #ddd;
342
+ border-radius: 8px;
343
+ box-shadow: 0 2px 10px rgba(0,0,0,0.1);
344
+ display: flex;
345
+ flex-direction: column;
346
+ z-index: 100;
347
+ overflow: hidden;
348
+ }
349
+
350
+ #cam-panel .panel-header {
351
+ padding: 12px;
352
+ background: #f8f8f8;
353
+ border-bottom: 1px solid #ddd;
354
+ display: flex;
355
+ justify-content: space-between;
356
+ align-items: center;
357
+ }
358
+
359
+ #cam-panel h3 {
360
+ margin: 0;
361
+ font-size: 14px;
362
+ font-weight: 600;
363
+ }
364
+
365
+ #cam-panel .panel-tabs {
366
+ display: flex;
367
+ border-bottom: 1px solid #ddd;
368
+ background: #fafafa;
369
+ }
370
+
371
+ #cam-panel .tab-btn {
372
+ flex: 1;
373
+ padding: 8px;
374
+ background: transparent;
375
+ border: none;
376
+ border-bottom: 2px solid transparent;
377
+ cursor: pointer;
378
+ font-size: 12px;
379
+ color: #666;
380
+ }
381
+
382
+ #cam-panel .tab-btn.active {
383
+ border-bottom-color: #d97706;
384
+ color: #d97706;
385
+ font-weight: 600;
386
+ }
387
+
388
+ #cam-panel .cam-tab {
389
+ padding: 12px;
390
+ overflow-y: auto;
391
+ flex: 1;
392
+ }
393
+
394
+ #cam-panel label {
395
+ display: block;
396
+ margin: 8px 0;
397
+ font-size: 12px;
398
+ color: #333;
399
+ }
400
+
401
+ #cam-panel input,
402
+ #cam-panel select {
403
+ width: 100%;
404
+ padding: 6px;
405
+ margin-top: 4px;
406
+ border: 1px solid #ddd;
407
+ border-radius: 4px;
408
+ font-size: 12px;
409
+ }
410
+
411
+ #cam-panel button {
412
+ width: 100%;
413
+ padding: 8px;
414
+ margin: 10px 0;
415
+ background: #d97706;
416
+ color: white;
417
+ border: none;
418
+ border-radius: 4px;
419
+ cursor: pointer;
420
+ font-size: 12px;
421
+ font-weight: 600;
422
+ }
423
+
424
+ #cam-panel button:hover {
425
+ background: #b45309;
426
+ }
427
+
428
+ #cam-slice-result,
429
+ #cam-nest-result,
430
+ #cam-toolpath-result,
431
+ #cam-estimate-result {
432
+ margin-top: 12px;
433
+ padding: 10px;
434
+ background: #f5f5f5;
435
+ border-radius: 4px;
436
+ font-size: 11px;
437
+ line-height: 1.5;
438
+ color: #333;
439
+ max-height: 300px;
440
+ overflow-y: auto;
441
+ }
442
+ </style>
443
+
444
+ <script>
445
+ function switchCamTab(tabName) {
446
+ document.querySelectorAll('.cam-tab').forEach(t => t.style.display = 'none');
447
+ document.querySelectorAll('.tab-btn').forEach(b => b.classList.remove('active'));
448
+ document.getElementById('cam-' + tabName + '-tab').style.display = 'block';
449
+ event.target.classList.add('active');
450
+ }
451
+
452
+ function camSlice() {
453
+ const selectedMesh = window._selectedMesh || window.allParts?.[0];
454
+ if (!selectedMesh) {
455
+ alert('No mesh selected');
456
+ return;
457
+ }
458
+
459
+ const result = window.cycleCAD.cam.slice(selectedMesh, {
460
+ layerHeight: parseFloat(document.getElementById('cam-layer-height').value),
461
+ infill: parseInt(document.getElementById('cam-infill').value),
462
+ material: document.getElementById('cam-material').value,
463
+ printer: document.getElementById('cam-printer').value
464
+ });
465
+
466
+ const html = `
467
+ <strong>${result.printer}</strong><br/>
468
+ Layers: ${result.totalLayers}<br/>
469
+ Material: ${result.materialWeightG}g (€${result.materialCostEUR})<br/>
470
+ Time: ${result.estimatedTimeReadable}<br/>
471
+ Build Volume: ${result.buildVolume.x}×${result.buildVolume.y}×${result.buildVolume.z}mm<br/>
472
+ Fits: ${result.fits ? '✓' : '✗'}<br/>
473
+ <button onclick="window.cycleCAD.cam.exportGcode('${result.gcode.replace(/'/g, "\\'")}', '${Date.now()}.gcode')">Download G-code</button>
474
+ `;
475
+ document.getElementById('cam-slice-result').innerHTML = html;
476
+ }
477
+
478
+ function camNest() {
479
+ // Placeholder — needs part data
480
+ alert('Nesting feature requires part data. See documentation.');
481
+ }
482
+
483
+ function camToolpath() {
484
+ const selectedMesh = window._selectedMesh || window.allParts?.[0];
485
+ if (!selectedMesh) {
486
+ alert('No mesh selected');
487
+ return;
488
+ }
489
+
490
+ const result = window.cycleCAD.cam.toolpath(selectedMesh, {
491
+ tool: document.getElementById('cam-tool').value,
492
+ strategy: document.getElementById('cam-strategy').value,
493
+ feedRate: parseInt(document.getElementById('cam-feed-rate').value),
494
+ machine: document.getElementById('cam-machine').value
495
+ });
496
+
497
+ const html = `
498
+ <strong>${result.machine}</strong><br/>
499
+ Tool: ${result.tool}<br/>
500
+ Strategy: ${result.strategy}<br/>
501
+ Passes: ${result.passes}<br/>
502
+ Path Length: ${result.totalLength}mm<br/>
503
+ Time: ${result.estimatedTimeReadable}<br/>
504
+ Fits: ${result.fits ? '✓' : '✗'}<br/>
505
+ <button onclick="window.cycleCAD.cam.exportGcode('${result.gcode.replace(/'/g, "\\'")}', '${Date.now()}.nc')">Download G-code</button>
506
+ `;
507
+ document.getElementById('cam-toolpath-result').innerHTML = html;
508
+ }
509
+
510
+ function camEstimate() {
511
+ const selectedMesh = window._selectedMesh || window.allParts?.[0];
512
+ if (!selectedMesh) {
513
+ alert('No mesh selected');
514
+ return;
515
+ }
516
+
517
+ const result = window.cycleCAD.cam.estimate(selectedMesh, {
518
+ process: document.getElementById('cam-process').value,
519
+ quantity: parseInt(document.getElementById('cam-quantity').value)
520
+ });
521
+
522
+ const html = `
523
+ <strong>${result.process}</strong><br/>
524
+ Machine: ${result.machine}<br/>
525
+ Volume: ${result.volumeCm3} cm³<br/>
526
+ Material Cost: €${result.materialCost}<br/>
527
+ Machine Cost: €${result.machineCost}<br/>
528
+ Total per Unit: €${result.totalPerUnit}<br/>
529
+ Total Batch (×${result.quantity}): €${result.totalBatch}<br/>
530
+ Time: ${result.timeMinutesReadable}
531
+ `;
532
+ document.getElementById('cam-estimate-result').innerHTML = html;
533
+ }
534
+
535
+ function camCompare() {
536
+ const selectedMesh = window._selectedMesh || window.allParts?.[0];
537
+ if (!selectedMesh) {
538
+ alert('No mesh selected');
539
+ return;
540
+ }
541
+
542
+ const result = window.cycleCAD.cam.compareCosts(selectedMesh, {material: 'pla'});
543
+
544
+ let html = `<strong>Cost Comparison</strong><br/>Volume: ${result.volumeCm3} cm³<br/><br/>`;
545
+ result.processes.forEach(p => {
546
+ html += `
547
+ <strong>${p.rank}. ${p.process}</strong><br/>
548
+ Total: €${p.totalCost} | Time: ${p.timeMinutes}min<br/>
549
+ ${p.costPerUnit ? `Per Unit: €${p.costPerUnit}<br/>` : ''}
550
+ Pros: ${p.pros.join(', ')}<br/>
551
+ <br/>
552
+ `;
553
+ });
554
+
555
+ document.getElementById('cam-estimate-result').innerHTML = html;
556
+ }
557
+ </script>
558
+ ```
559
+
560
+ ## Usage from Agent API
561
+
562
+ The CAM module is automatically registered as `window.cycleCAD.cam` and can be called from agent commands:
563
+
564
+ ```javascript
565
+ // From agent-api.js:
566
+ 'cam.slice': async ({ printer, layerHeight, infill, material }) => {
567
+ const mesh = getSelectedMesh(); // Assuming available
568
+ return window.cycleCAD.cam.slice(mesh, { printer, layerHeight, infill, material });
569
+ }
570
+ ```
571
+
572
+ ## Testing
573
+
574
+ ```javascript
575
+ // In browser console:
576
+ const mesh = window.allParts[0]; // Get a part
577
+ const result = window.cycleCAD.cam.slice(mesh, {
578
+ printer: 'ender3',
579
+ layerHeight: 0.2,
580
+ infill: 20
581
+ });
582
+ console.log(result);
583
+
584
+ // Download G-code
585
+ window.cycleCAD.cam.exportGcode(result.gcode, 'test.gcode');
586
+ ```
587
+
588
+ ## Feature Coverage
589
+
590
+ | Feature | Status | Details |
591
+ |---------|--------|---------|
592
+ | FDM Slicing | ✅ | 3 printer profiles, realistic time estimation |
593
+ | G-code Generation | ✅ | Simplified but valid for most slicers |
594
+ | Cost Estimation | ✅ | Material + machine time pricing |
595
+ | 2D Nesting | ✅ | Bottom-left packing algorithm |
596
+ | CNC Toolpath | ✅ | 3 strategies, 10 tools, realistic feed rates |
597
+ | SLA Printing | ✅ | Elegoo, Formlabs profiles |
598
+ | Laser Cutting | ✅ | K40, xTool, Glowforge profiles |
599
+ | Cost Comparison | ✅ | FDM vs CNC vs SLA vs Laser vs Injection |
600
+ | SVG Export | ✅ | Nesting visualization |
601
+
602
+ ## Notes
603
+
604
+ - G-code output is simplified and intended for preview/testing
605
+ - For production, recommend using dedicated slicers (Cura, PrusaSlicer, Fusion 360 CAM)
606
+ - Material costs are averages and vary by supplier
607
+ - Machine profiles are based on official specs
608
+ - Nesting algorithm is greedy (not optimal); for production use dedicated nesting software
609
+
610
+ ---
611
+
612
+ **Module created by Claude Code on 2026-03-26. Slide 10 implementation: "Prepare — Slice / Nest / Toolpath / G-code Generation."**