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.
- package/API-BUILD-MANIFEST.txt +339 -0
- package/API-SERVER.md +535 -0
- package/Architecture-Deck.pptx +0 -0
- package/CLAUDE.md +172 -11
- package/CLI-BUILD-SUMMARY.md +504 -0
- package/CLI-INDEX.md +356 -0
- package/CLI-README.md +466 -0
- package/COLLABORATION-INTEGRATION-GUIDE.md +325 -0
- package/CONNECTED_FABS_GUIDE.md +612 -0
- package/CONNECTED_FABS_README.md +310 -0
- package/DELIVERABLES.md +343 -0
- package/DFM-ANALYZER-INTEGRATION.md +368 -0
- package/DFM-QUICK-START.js +253 -0
- package/Dockerfile +69 -0
- package/IMPLEMENTATION.md +327 -0
- package/LICENSE +31 -0
- package/MARKETPLACE_QUICK_REFERENCE.txt +294 -0
- package/MCP-INDEX.md +264 -0
- package/QUICKSTART-API.md +388 -0
- package/QUICKSTART-CLI.md +211 -0
- package/QUICKSTART-MCP.md +196 -0
- package/README-MCP.md +208 -0
- package/TEST-TOKEN-ENGINE.md +319 -0
- package/TOKEN-ENGINE-SUMMARY.md +266 -0
- package/TOKENS-README.md +263 -0
- package/TOOLS-REFERENCE.md +254 -0
- package/app/index.html +168 -3
- package/app/js/TOKEN-INTEGRATION.md +391 -0
- package/app/js/agent-api.js +3 -3
- package/app/js/ai-copilot.js +1435 -0
- package/app/js/cam-pipeline.js +840 -0
- package/app/js/collaboration-ui.js +995 -0
- package/app/js/collaboration.js +1116 -0
- package/app/js/connected-fabs-example.js +404 -0
- package/app/js/connected-fabs.js +1449 -0
- package/app/js/dfm-analyzer.js +1760 -0
- package/app/js/marketplace.js +1994 -0
- package/app/js/material-library.js +2115 -0
- package/app/js/token-dashboard.js +563 -0
- package/app/js/token-engine.js +743 -0
- package/app/test-agent.html +1801 -0
- package/bin/cyclecad-cli.js +662 -0
- package/bin/cyclecad-mcp +2 -0
- package/bin/server.js +242 -0
- package/cycleCAD-Architecture.pptx +0 -0
- package/cycleCAD-Investor-Deck.pptx +0 -0
- package/demo-mcp.sh +60 -0
- package/docs/API-SERVER-SUMMARY.md +375 -0
- package/docs/API-SERVER.md +667 -0
- package/docs/CAM-EXAMPLES.md +344 -0
- package/docs/CAM-INTEGRATION.md +612 -0
- package/docs/CAM-QUICK-REFERENCE.md +199 -0
- package/docs/CLI-INTEGRATION.md +510 -0
- package/docs/CLI.md +872 -0
- package/docs/MARKETPLACE-API-SCHEMA.json +564 -0
- package/docs/MARKETPLACE-INTEGRATION.md +467 -0
- package/docs/MARKETPLACE-SETUP.html +439 -0
- package/docs/MCP-SERVER.md +403 -0
- package/examples/api-client-example.js +488 -0
- package/examples/api-client-example.py +359 -0
- package/examples/batch-manufacturing.txt +28 -0
- package/examples/batch-simple.txt +26 -0
- package/model-marketplace.html +1273 -0
- package/package.json +14 -3
- package/server/api-server.js +1120 -0
- package/server/mcp-server.js +1161 -0
- package/test-api-server.js +432 -0
- package/test-mcp.js +198 -0
- 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."**
|