cyclecad 3.2.0 → 3.4.0
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/DOCKER-SETUP-VERIFICATION.md +399 -0
- package/DOCKER-TESTING.md +463 -0
- package/FUSION360_MODULES.md +478 -0
- package/FUSION_MODULES_README.md +352 -0
- package/INTEGRATION_SNIPPETS.md +608 -0
- package/KILLER-FEATURES-DELIVERY.md +469 -0
- package/MODULES_SUMMARY.txt +337 -0
- package/QUICK_REFERENCE.txt +298 -0
- package/README-DOCKER-TESTING.txt +438 -0
- package/app/index.html +23 -10
- package/app/js/fusion-help.json +1808 -0
- package/app/js/help-module-v3.js +1096 -0
- package/app/js/killer-features-help.json +395 -0
- package/app/js/killer-features.js +1508 -0
- package/app/js/modules/fusion-assembly.js +842 -0
- package/app/js/modules/fusion-cam.js +785 -0
- package/app/js/modules/fusion-data.js +814 -0
- package/app/js/modules/fusion-drawing.js +844 -0
- package/app/js/modules/fusion-inspection.js +756 -0
- package/app/js/modules/fusion-render.js +774 -0
- package/app/js/modules/fusion-simulation.js +986 -0
- package/app/js/modules/fusion-sketch.js +1044 -0
- package/app/js/modules/fusion-solid.js +1095 -0
- package/app/js/modules/fusion-surface.js +949 -0
- package/app/tests/FUSION_TEST_SUITE.md +266 -0
- package/app/tests/README.md +77 -0
- package/app/tests/TESTING-CHECKLIST.md +177 -0
- package/app/tests/TEST_SUITE_SUMMARY.txt +236 -0
- package/app/tests/brep-live-test.html +848 -0
- package/app/tests/docker-integration-test.html +811 -0
- package/app/tests/fusion-all-tests.html +670 -0
- package/app/tests/fusion-assembly-tests.html +461 -0
- package/app/tests/fusion-cam-tests.html +421 -0
- package/app/tests/fusion-simulation-tests.html +421 -0
- package/app/tests/fusion-sketch-tests.html +613 -0
- package/app/tests/fusion-solid-tests.html +529 -0
- package/app/tests/index.html +453 -0
- package/app/tests/killer-features-test.html +509 -0
- package/app/tests/run-tests.html +874 -0
- package/app/tests/step-import-live-test.html +1115 -0
- package/app/tests/test-agent-v3.html +93 -696
- package/architecture-dashboard.html +1970 -0
- package/docs/API-REFERENCE.md +1423 -0
- package/docs/BREP-LIVE-TEST-GUIDE.md +453 -0
- package/docs/DEVELOPER-GUIDE-v3.md +795 -0
- package/docs/DOCKER-QUICK-TEST.md +376 -0
- package/docs/FUSION-FEATURES-GUIDE.md +2513 -0
- package/docs/FUSION-TUTORIAL.md +1203 -0
- package/docs/INFRASTRUCTURE-GUIDE-INDEX.md +327 -0
- package/docs/KEYBOARD-SHORTCUTS.md +402 -0
- package/docs/KILLER-FEATURES-INTEGRATION.md +412 -0
- package/docs/KILLER-FEATURES-SUMMARY.md +424 -0
- package/docs/KILLER-FEATURES-TUTORIAL.md +784 -0
- package/docs/KILLER-FEATURES.md +562 -0
- package/docs/QUICK-REFERENCE.md +282 -0
- package/docs/README-v3-DOCS.md +274 -0
- package/docs/TUTORIAL-v3.md +1190 -0
- package/docs/architecture-dashboard.html +1970 -0
- package/docs/architecture-v3.html +1038 -0
- package/linkedin-post-v3.md +58 -0
- package/package.json +1 -1
- package/scripts/dev-setup.sh +338 -0
- package/scripts/docker-health-check.sh +159 -0
- package/scripts/integration-test.sh +311 -0
- package/scripts/test-docker.sh +515 -0
|
@@ -0,0 +1,608 @@
|
|
|
1
|
+
# Integration Snippets for Fusion 360 Modules
|
|
2
|
+
|
|
3
|
+
Ready-to-paste code for integrating fusion-sketch.js, fusion-solid.js, and fusion-surface.js into cycleCAD.
|
|
4
|
+
|
|
5
|
+
---
|
|
6
|
+
|
|
7
|
+
## 1. Add Module Imports to `app/index.html`
|
|
8
|
+
|
|
9
|
+
**Location:** Inside the main `<script type="module">` tag
|
|
10
|
+
|
|
11
|
+
```html
|
|
12
|
+
<script type="module">
|
|
13
|
+
// Existing imports...
|
|
14
|
+
import { initViewport, ... } from './js/viewport.js';
|
|
15
|
+
|
|
16
|
+
// ADD THESE LINES:
|
|
17
|
+
import fusionSketch from './js/modules/fusion-sketch.js';
|
|
18
|
+
import fusionSolid from './js/modules/fusion-solid.js';
|
|
19
|
+
import fusionSurface from './js/modules/fusion-surface.js';
|
|
20
|
+
|
|
21
|
+
// Initialize app...
|
|
22
|
+
const APP = { ... };
|
|
23
|
+
|
|
24
|
+
// ADD MODULE REGISTRY:
|
|
25
|
+
APP.modules = {
|
|
26
|
+
sketch: fusionSketch,
|
|
27
|
+
solid: fusionSolid,
|
|
28
|
+
surface: fusionSurface,
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
// Initialize modules
|
|
32
|
+
Object.values(APP.modules).forEach(mod => {
|
|
33
|
+
if (mod.init) mod.init();
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
// Expose to window for agent API
|
|
37
|
+
window.cycleCAD = {
|
|
38
|
+
APP,
|
|
39
|
+
modules: APP.modules,
|
|
40
|
+
async execute(namespace, command, params = {}) {
|
|
41
|
+
const [ns, cmd] = namespace.includes('.')
|
|
42
|
+
? namespace.split('.')
|
|
43
|
+
: [namespace, command];
|
|
44
|
+
|
|
45
|
+
const module = APP.modules[ns];
|
|
46
|
+
if (!module) {
|
|
47
|
+
return { success: false, message: `Module ${ns} not found` };
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
return module.execute(cmd, params);
|
|
51
|
+
}
|
|
52
|
+
};
|
|
53
|
+
</script>
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## 2. Add Toolbar Buttons
|
|
59
|
+
|
|
60
|
+
**Location:** In the workspace toolbar area of `app/index.html` (after existing tabs)
|
|
61
|
+
|
|
62
|
+
```html
|
|
63
|
+
<!-- Sketch Toolbar Tab -->
|
|
64
|
+
<div id="sketch-tab" class="tb-tab" data-tab="sketch" style="display:none;">
|
|
65
|
+
<button class="tb-btn" id="sketch-start-btn" title="Start Sketch (K)">
|
|
66
|
+
<span>Sketch</span>
|
|
67
|
+
</button>
|
|
68
|
+
<div class="tb-divider"></div>
|
|
69
|
+
<button class="tb-btn" id="sketch-line-btn" title="Line (L)">Line</button>
|
|
70
|
+
<button class="tb-btn" id="sketch-rect-btn" title="Rectangle (R)">Rectangle</button>
|
|
71
|
+
<button class="tb-btn" id="sketch-circle-btn" title="Circle (C)">Circle</button>
|
|
72
|
+
<button class="tb-btn" id="sketch-arc-btn" title="Arc (A)">Arc</button>
|
|
73
|
+
<button class="tb-btn" id="sketch-ellipse-btn" title="Ellipse (E)">Ellipse</button>
|
|
74
|
+
<button class="tb-btn" id="sketch-spline-btn" title="Spline (S)">Spline</button>
|
|
75
|
+
<button class="tb-btn" id="sketch-polygon-btn" title="Polygon (P)">Polygon</button>
|
|
76
|
+
<div class="tb-divider"></div>
|
|
77
|
+
<button class="tb-btn" id="sketch-mirror-btn" title="Mirror">Mirror</button>
|
|
78
|
+
<button class="tb-btn" id="sketch-offset-btn" title="Offset">Offset</button>
|
|
79
|
+
<button class="tb-btn" id="sketch-trim-btn" title="Trim">Trim</button>
|
|
80
|
+
<button class="tb-btn" id="sketch-fillet-btn" title="Fillet 2D">Fillet 2D</button>
|
|
81
|
+
<button class="tb-btn" id="sketch-end-btn" title="End Sketch (Escape)">✓ End</button>
|
|
82
|
+
</div>
|
|
83
|
+
|
|
84
|
+
<!-- Solid Toolbar Tab -->
|
|
85
|
+
<div id="solid-tab" class="tb-tab" data-tab="solid" style="display:none;">
|
|
86
|
+
<button class="tb-btn" id="solid-extrude-btn" title="Extrude (E)">Extrude</button>
|
|
87
|
+
<button class="tb-btn" id="solid-revolve-btn" title="Revolve (V)">Revolve</button>
|
|
88
|
+
<button class="tb-btn" id="solid-sweep-btn" title="Sweep">Sweep</button>
|
|
89
|
+
<button class="tb-btn" id="solid-loft-btn" title="Loft">Loft</button>
|
|
90
|
+
<div class="tb-divider"></div>
|
|
91
|
+
<button class="tb-btn" id="solid-hole-btn" title="Hole">Hole</button>
|
|
92
|
+
<button class="tb-btn" id="solid-thread-btn" title="Thread">Thread</button>
|
|
93
|
+
<button class="tb-btn" id="solid-fillet-btn" title="Fillet (F)">Fillet</button>
|
|
94
|
+
<button class="tb-btn" id="solid-chamfer-btn" title="Chamfer (C)">Chamfer</button>
|
|
95
|
+
<div class="tb-divider"></div>
|
|
96
|
+
<button class="tb-btn" id="solid-shell-btn" title="Shell">Shell</button>
|
|
97
|
+
<button class="tb-btn" id="solid-mirror-btn" title="Mirror (M)">Mirror</button>
|
|
98
|
+
<button class="tb-btn" id="solid-pattern-btn" title="Pattern (P)">Pattern</button>
|
|
99
|
+
<button class="tb-btn" id="solid-combine-btn" title="Boolean">Boolean</button>
|
|
100
|
+
</div>
|
|
101
|
+
|
|
102
|
+
<!-- Surface Toolbar Tab -->
|
|
103
|
+
<div id="surface-tab" class="tb-tab" data-tab="surface" style="display:none;">
|
|
104
|
+
<button class="tb-btn" id="surface-extrude-btn" title="Extrude Surface">Extrude</button>
|
|
105
|
+
<button class="tb-btn" id="surface-revolve-btn" title="Revolve Surface">Revolve</button>
|
|
106
|
+
<button class="tb-btn" id="surface-sweep-btn" title="Sweep Surface">Sweep</button>
|
|
107
|
+
<button class="tb-btn" id="surface-loft-btn" title="Loft Surface">Loft</button>
|
|
108
|
+
<div class="tb-divider"></div>
|
|
109
|
+
<button class="tb-btn" id="surface-patch-btn" title="Patch">Patch</button>
|
|
110
|
+
<button class="tb-btn" id="surface-offset-btn" title="Offset">Offset</button>
|
|
111
|
+
<button class="tb-btn" id="surface-trim-btn" title="Trim">Trim</button>
|
|
112
|
+
<div class="tb-divider"></div>
|
|
113
|
+
<button class="tb-btn" id="surface-stitch-btn" title="Stitch">Stitch</button>
|
|
114
|
+
<button class="tb-btn" id="surface-sculpt-btn" title="Sculpt (T)">Sculpt</button>
|
|
115
|
+
<button class="tb-btn" id="surface-ruled-btn" title="Ruled">Ruled</button>
|
|
116
|
+
</div>
|
|
117
|
+
```
|
|
118
|
+
|
|
119
|
+
---
|
|
120
|
+
|
|
121
|
+
## 3. Add Tab Switching to `app/js/app.js`
|
|
122
|
+
|
|
123
|
+
```javascript
|
|
124
|
+
// Tab switching for sketch/solid/surface tabs
|
|
125
|
+
document.addEventListener('click', (event) => {
|
|
126
|
+
const tabBtn = event.target.closest('[data-tab]');
|
|
127
|
+
if (!tabBtn) return;
|
|
128
|
+
|
|
129
|
+
const tabName = tabBtn.dataset.tab;
|
|
130
|
+
|
|
131
|
+
// Hide all tabs
|
|
132
|
+
document.querySelectorAll('.tb-tab').forEach(tab => {
|
|
133
|
+
tab.style.display = 'none';
|
|
134
|
+
});
|
|
135
|
+
|
|
136
|
+
// Show selected tab
|
|
137
|
+
const selectedTab = document.getElementById(`${tabName}-tab`);
|
|
138
|
+
if (selectedTab) {
|
|
139
|
+
selectedTab.style.display = 'flex';
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
// Update UI panel
|
|
143
|
+
const module = APP.modules[tabName];
|
|
144
|
+
if (module && module.getUI) {
|
|
145
|
+
const panel = document.getElementById('properties-panel');
|
|
146
|
+
if (panel) {
|
|
147
|
+
panel.innerHTML = module.getUI();
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
---
|
|
154
|
+
|
|
155
|
+
## 4. Sketch Event Handlers
|
|
156
|
+
|
|
157
|
+
**Location:** Add to `app/js/app.js` or `app/js/modules/sketch-handlers.js`
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
let sketchActive = false;
|
|
161
|
+
let sketchPlane = 'XY';
|
|
162
|
+
|
|
163
|
+
// Start sketch
|
|
164
|
+
document.getElementById('sketch-start-btn')?.addEventListener('click', async () => {
|
|
165
|
+
if (sketchActive) {
|
|
166
|
+
// End sketch
|
|
167
|
+
const result = await APP.modules.sketch.endSketch();
|
|
168
|
+
console.log('Sketch ended:', result);
|
|
169
|
+
sketchActive = false;
|
|
170
|
+
document.getElementById('sketch-start-btn').textContent = 'Sketch';
|
|
171
|
+
} else {
|
|
172
|
+
// Start sketch
|
|
173
|
+
const result = await APP.modules.sketch.startSketch(sketchPlane, APP.scene, APP.renderer);
|
|
174
|
+
console.log('Sketch started:', result);
|
|
175
|
+
sketchActive = true;
|
|
176
|
+
document.getElementById('sketch-start-btn').textContent = '✓ Sketch';
|
|
177
|
+
}
|
|
178
|
+
});
|
|
179
|
+
|
|
180
|
+
// Tool selection
|
|
181
|
+
const sketchTools = [
|
|
182
|
+
{ id: 'sketch-line-btn', tool: 'line' },
|
|
183
|
+
{ id: 'sketch-rect-btn', tool: 'rectangle' },
|
|
184
|
+
{ id: 'sketch-circle-btn', tool: 'circle' },
|
|
185
|
+
{ id: 'sketch-arc-btn', tool: 'arc' },
|
|
186
|
+
{ id: 'sketch-ellipse-btn', tool: 'ellipse' },
|
|
187
|
+
{ id: 'sketch-spline-btn', tool: 'spline' },
|
|
188
|
+
{ id: 'sketch-polygon-btn', tool: 'polygon' },
|
|
189
|
+
{ id: 'sketch-mirror-btn', tool: 'mirror' },
|
|
190
|
+
{ id: 'sketch-offset-btn', tool: 'offset' },
|
|
191
|
+
{ id: 'sketch-trim-btn', tool: 'trim' },
|
|
192
|
+
{ id: 'sketch-fillet-btn', tool: 'fillet2d' },
|
|
193
|
+
];
|
|
194
|
+
|
|
195
|
+
sketchTools.forEach(({ id, tool }) => {
|
|
196
|
+
document.getElementById(id)?.addEventListener('click', () => {
|
|
197
|
+
if (sketchActive) {
|
|
198
|
+
APP.modules.sketch.setTool(tool);
|
|
199
|
+
document.querySelectorAll('#sketch-tab .tb-btn').forEach(btn => {
|
|
200
|
+
btn.style.opacity = '0.6';
|
|
201
|
+
});
|
|
202
|
+
document.getElementById(id).style.opacity = '1';
|
|
203
|
+
} else {
|
|
204
|
+
alert('Start a sketch first');
|
|
205
|
+
}
|
|
206
|
+
});
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
// Viewport click handling for sketch points
|
|
210
|
+
document.getElementById('viewport').addEventListener('click', (event) => {
|
|
211
|
+
if (!sketchActive) return;
|
|
212
|
+
|
|
213
|
+
const rect = event.target.getBoundingClientRect();
|
|
214
|
+
const x = event.clientX - rect.left;
|
|
215
|
+
const y = event.clientY - rect.top;
|
|
216
|
+
|
|
217
|
+
// Convert screen coords to world coords (simplified)
|
|
218
|
+
const worldX = (x / rect.width) * 100 - 50;
|
|
219
|
+
const worldY = (y / rect.height) * 100 - 50;
|
|
220
|
+
|
|
221
|
+
APP.modules.sketch.addPoint(worldX, worldY, true);
|
|
222
|
+
});
|
|
223
|
+
```
|
|
224
|
+
|
|
225
|
+
---
|
|
226
|
+
|
|
227
|
+
## 5. Solid Operation Handlers
|
|
228
|
+
|
|
229
|
+
**Location:** Add to `app/js/app.js`
|
|
230
|
+
|
|
231
|
+
```javascript
|
|
232
|
+
let selectedGeometry = null;
|
|
233
|
+
let selectedBodyId = null;
|
|
234
|
+
|
|
235
|
+
// Extrude
|
|
236
|
+
document.getElementById('solid-extrude-btn')?.addEventListener('click', async () => {
|
|
237
|
+
if (!selectedGeometry) {
|
|
238
|
+
alert('Select a sketch first');
|
|
239
|
+
return;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
const result = await APP.modules.solid.extrude(selectedGeometry, {
|
|
243
|
+
distance: 10,
|
|
244
|
+
direction: 'positive',
|
|
245
|
+
taperAngle: 0,
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
if (result.success) {
|
|
249
|
+
APP.scene.add(result.body.mesh);
|
|
250
|
+
console.log('Body extruded:', result.body);
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
|
|
254
|
+
// Revolve
|
|
255
|
+
document.getElementById('solid-revolve-btn')?.addEventListener('click', async () => {
|
|
256
|
+
if (!selectedGeometry) {
|
|
257
|
+
alert('Select a sketch first');
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
|
|
261
|
+
const result = await APP.modules.solid.revolve(selectedGeometry, 'Z', {
|
|
262
|
+
angle: Math.PI * 2,
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
if (result.success) {
|
|
266
|
+
APP.scene.add(result.body.mesh);
|
|
267
|
+
}
|
|
268
|
+
});
|
|
269
|
+
|
|
270
|
+
// Fillet
|
|
271
|
+
document.getElementById('solid-fillet-btn')?.addEventListener('click', async () => {
|
|
272
|
+
if (!selectedBodyId) {
|
|
273
|
+
alert('Select a body first');
|
|
274
|
+
return;
|
|
275
|
+
}
|
|
276
|
+
|
|
277
|
+
const result = await APP.modules.solid.fillet(selectedBodyId, [0, 1, 2], {
|
|
278
|
+
radius: 2,
|
|
279
|
+
type: 'constant',
|
|
280
|
+
});
|
|
281
|
+
|
|
282
|
+
if (result.success) {
|
|
283
|
+
console.log('Fillet applied');
|
|
284
|
+
}
|
|
285
|
+
});
|
|
286
|
+
|
|
287
|
+
// Chamfer
|
|
288
|
+
document.getElementById('solid-chamfer-btn')?.addEventListener('click', async () => {
|
|
289
|
+
if (!selectedBodyId) {
|
|
290
|
+
alert('Select a body first');
|
|
291
|
+
return;
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
const result = await APP.modules.solid.chamfer(selectedBodyId, [0, 1, 2], {
|
|
295
|
+
distance: 1,
|
|
296
|
+
angle: 45,
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
if (result.success) {
|
|
300
|
+
console.log('Chamfer applied');
|
|
301
|
+
}
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
// Mirror
|
|
305
|
+
document.getElementById('solid-mirror-btn')?.addEventListener('click', async () => {
|
|
306
|
+
if (!selectedBodyId) {
|
|
307
|
+
alert('Select a body first');
|
|
308
|
+
return;
|
|
309
|
+
}
|
|
310
|
+
|
|
311
|
+
const result = await APP.modules.solid.mirror(selectedBodyId, {
|
|
312
|
+
plane: 'XY',
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
if (result.success) {
|
|
316
|
+
APP.scene.add(result.body.mesh);
|
|
317
|
+
}
|
|
318
|
+
});
|
|
319
|
+
|
|
320
|
+
// Pattern
|
|
321
|
+
document.getElementById('solid-pattern-btn')?.addEventListener('click', async () => {
|
|
322
|
+
if (!selectedBodyId) {
|
|
323
|
+
alert('Select a body first');
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
|
|
327
|
+
const result = await APP.modules.solid.pattern(selectedBodyId, {
|
|
328
|
+
type: 'rectangular',
|
|
329
|
+
count: 3,
|
|
330
|
+
distance: 20,
|
|
331
|
+
direction: 'X',
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
if (result.success) {
|
|
335
|
+
result.patternedBodies.forEach(body => APP.scene.add(body.mesh));
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
---
|
|
341
|
+
|
|
342
|
+
## 6. Surface Operation Handlers
|
|
343
|
+
|
|
344
|
+
**Location:** Add to `app/js/app.js`
|
|
345
|
+
|
|
346
|
+
```javascript
|
|
347
|
+
let selectedSurfaceId = null;
|
|
348
|
+
|
|
349
|
+
// Extrude Surface
|
|
350
|
+
document.getElementById('surface-extrude-btn')?.addEventListener('click', async () => {
|
|
351
|
+
if (!selectedGeometry) {
|
|
352
|
+
alert('Select a surface first');
|
|
353
|
+
return;
|
|
354
|
+
}
|
|
355
|
+
|
|
356
|
+
const result = await APP.modules.surface.extrudeSurface(selectedGeometry, {
|
|
357
|
+
distance: 10,
|
|
358
|
+
direction: 'positive',
|
|
359
|
+
symmetric: false,
|
|
360
|
+
});
|
|
361
|
+
|
|
362
|
+
if (result.success) {
|
|
363
|
+
APP.scene.add(result.surface.mesh);
|
|
364
|
+
}
|
|
365
|
+
});
|
|
366
|
+
|
|
367
|
+
// Loft Surface
|
|
368
|
+
document.getElementById('surface-loft-btn')?.addEventListener('click', async () => {
|
|
369
|
+
if (!selectedGeometry) {
|
|
370
|
+
alert('Select profiles first');
|
|
371
|
+
return;
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
const result = await APP.modules.surface.loftSurface([selectedGeometry], {
|
|
375
|
+
matchPeaks: false,
|
|
376
|
+
});
|
|
377
|
+
|
|
378
|
+
if (result.success) {
|
|
379
|
+
APP.scene.add(result.surface.mesh);
|
|
380
|
+
}
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
// Sculpt
|
|
384
|
+
document.getElementById('surface-sculpt-btn')?.addEventListener('click', async () => {
|
|
385
|
+
if (!selectedSurfaceId) {
|
|
386
|
+
alert('Select a surface first');
|
|
387
|
+
return;
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
const result = await APP.modules.surface.sculptSurface(selectedSurfaceId);
|
|
391
|
+
|
|
392
|
+
if (result.success) {
|
|
393
|
+
console.log('Sculpt mode enabled, control points:', result.controlPointCount);
|
|
394
|
+
}
|
|
395
|
+
});
|
|
396
|
+
|
|
397
|
+
// Finish Sculpt (when button appears)
|
|
398
|
+
document.addEventListener('click', (event) => {
|
|
399
|
+
if (event.target.id === 'finish-sculpt') {
|
|
400
|
+
APP.modules.surface.finishSculpt();
|
|
401
|
+
console.log('Sculpt finished');
|
|
402
|
+
}
|
|
403
|
+
});
|
|
404
|
+
|
|
405
|
+
// Trim Surface
|
|
406
|
+
document.getElementById('surface-trim-btn')?.addEventListener('click', async () => {
|
|
407
|
+
if (!selectedSurfaceId) {
|
|
408
|
+
alert('Select a surface first');
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const result = await APP.modules.surface.trimSurface(
|
|
413
|
+
selectedSurfaceId,
|
|
414
|
+
'surface_1', // Tool surface ID
|
|
415
|
+
{ removeInside: true }
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
if (result.success) {
|
|
419
|
+
APP.scene.add(result.surface.mesh);
|
|
420
|
+
}
|
|
421
|
+
});
|
|
422
|
+
```
|
|
423
|
+
|
|
424
|
+
---
|
|
425
|
+
|
|
426
|
+
## 7. Agent API Usage
|
|
427
|
+
|
|
428
|
+
**For AI agents or automations:**
|
|
429
|
+
|
|
430
|
+
```javascript
|
|
431
|
+
// Via window.cycleCAD
|
|
432
|
+
const result = await window.cycleCAD.execute('sketch', 'startSketch', {
|
|
433
|
+
plane: 'XY'
|
|
434
|
+
});
|
|
435
|
+
|
|
436
|
+
// Draw a rectangle
|
|
437
|
+
await window.cycleCAD.execute('sketch', 'setTool', { tool: 'rectangle' });
|
|
438
|
+
await window.cycleCAD.execute('sketch', 'addPoint', { x: 0, y: 0 });
|
|
439
|
+
await window.cycleCAD.execute('sketch', 'addPoint', { x: 20, y: 10 });
|
|
440
|
+
|
|
441
|
+
// Extrude
|
|
442
|
+
const sketchData = await window.cycleCAD.execute('sketch', 'endSketch');
|
|
443
|
+
const extrusionResult = await window.cycleCAD.execute('solid', 'extrude', {
|
|
444
|
+
geometry: profileGeometry,
|
|
445
|
+
distance: 15,
|
|
446
|
+
});
|
|
447
|
+
|
|
448
|
+
// Fillet
|
|
449
|
+
if (extrusionResult.success) {
|
|
450
|
+
await window.cycleCAD.execute('solid', 'fillet', {
|
|
451
|
+
bodyId: extrusionResult.body.id,
|
|
452
|
+
edgeIds: [0, 1, 2],
|
|
453
|
+
radius: 2,
|
|
454
|
+
});
|
|
455
|
+
}
|
|
456
|
+
```
|
|
457
|
+
|
|
458
|
+
---
|
|
459
|
+
|
|
460
|
+
## 8. Keyboard Shortcuts
|
|
461
|
+
|
|
462
|
+
**Location:** Add to `app/js/shortcuts.js`
|
|
463
|
+
|
|
464
|
+
```javascript
|
|
465
|
+
const sketchShortcuts = {
|
|
466
|
+
'KeyK': () => APP.modules.sketch.startSketch('XY', APP.scene, APP.renderer),
|
|
467
|
+
'KeyL': () => APP.modules.sketch.setTool('line'),
|
|
468
|
+
'KeyR': () => APP.modules.sketch.setTool('rectangle'),
|
|
469
|
+
'KeyC': () => APP.modules.sketch.setTool('circle'),
|
|
470
|
+
'KeyA': () => APP.modules.sketch.setTool('arc'),
|
|
471
|
+
'KeyS': () => APP.modules.sketch.setTool('spline'),
|
|
472
|
+
'KeyP': () => APP.modules.sketch.setTool('polygon'),
|
|
473
|
+
'Escape': () => APP.modules.sketch.endSketch(),
|
|
474
|
+
};
|
|
475
|
+
|
|
476
|
+
const solidShortcuts = {
|
|
477
|
+
'KeyE': () => document.getElementById('solid-extrude-btn')?.click(),
|
|
478
|
+
'KeyV': () => document.getElementById('solid-revolve-btn')?.click(),
|
|
479
|
+
'KeyF': () => document.getElementById('solid-fillet-btn')?.click(),
|
|
480
|
+
'KeyM': () => document.getElementById('solid-mirror-btn')?.click(),
|
|
481
|
+
'KeyP': () => document.getElementById('solid-pattern-btn')?.click(),
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
document.addEventListener('keydown', (event) => {
|
|
485
|
+
const handler = sketchShortcuts[event.code] || solidShortcuts[event.code];
|
|
486
|
+
if (handler) {
|
|
487
|
+
handler();
|
|
488
|
+
}
|
|
489
|
+
});
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
---
|
|
493
|
+
|
|
494
|
+
## 9. CSS Styling (Optional)
|
|
495
|
+
|
|
496
|
+
**Add to `app/index.html` or `app/css/main.css`:**
|
|
497
|
+
|
|
498
|
+
```css
|
|
499
|
+
.tb-tab {
|
|
500
|
+
display: none;
|
|
501
|
+
flex: 0 1 auto;
|
|
502
|
+
gap: 4px;
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
.tb-tab.active {
|
|
506
|
+
display: flex;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
.tb-btn {
|
|
510
|
+
padding: 6px 12px;
|
|
511
|
+
background: var(--bg-tertiary);
|
|
512
|
+
color: var(--text-primary);
|
|
513
|
+
border: 1px solid var(--border-color);
|
|
514
|
+
border-radius: 3px;
|
|
515
|
+
cursor: pointer;
|
|
516
|
+
font-size: 12px;
|
|
517
|
+
font-weight: 500;
|
|
518
|
+
transition: all var(--transition-fast);
|
|
519
|
+
white-space: nowrap;
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
.tb-btn:hover {
|
|
523
|
+
background: var(--accent-blue);
|
|
524
|
+
color: white;
|
|
525
|
+
}
|
|
526
|
+
|
|
527
|
+
.tb-btn.active {
|
|
528
|
+
background: var(--accent-blue);
|
|
529
|
+
color: white;
|
|
530
|
+
border-color: var(--accent-blue);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
.tb-divider {
|
|
534
|
+
width: 1px;
|
|
535
|
+
height: 24px;
|
|
536
|
+
background: var(--border-color);
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
#sketch-panel,
|
|
540
|
+
#solid-panel,
|
|
541
|
+
#surface-panel {
|
|
542
|
+
display: grid;
|
|
543
|
+
gap: 12px;
|
|
544
|
+
padding: 12px;
|
|
545
|
+
background: var(--bg-secondary);
|
|
546
|
+
border-radius: 4px;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
#sketch-panel h3,
|
|
550
|
+
#solid-panel h3,
|
|
551
|
+
#surface-panel h3 {
|
|
552
|
+
margin: 0;
|
|
553
|
+
font-size: 13px;
|
|
554
|
+
font-weight: 600;
|
|
555
|
+
color: var(--text-primary);
|
|
556
|
+
}
|
|
557
|
+
|
|
558
|
+
#sketch-panel button,
|
|
559
|
+
#solid-panel button,
|
|
560
|
+
#surface-panel button {
|
|
561
|
+
padding: 4px 8px;
|
|
562
|
+
margin: 2px;
|
|
563
|
+
background: var(--accent-blue);
|
|
564
|
+
color: white;
|
|
565
|
+
border: none;
|
|
566
|
+
border-radius: 2px;
|
|
567
|
+
cursor: pointer;
|
|
568
|
+
font-size: 11px;
|
|
569
|
+
}
|
|
570
|
+
|
|
571
|
+
#sketch-panel button:hover,
|
|
572
|
+
#solid-panel button:hover,
|
|
573
|
+
#surface-panel button:hover {
|
|
574
|
+
background: var(--accent-blue-hover);
|
|
575
|
+
}
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
---
|
|
579
|
+
|
|
580
|
+
## 10. Testing
|
|
581
|
+
|
|
582
|
+
**Quick test in browser console:**
|
|
583
|
+
|
|
584
|
+
```javascript
|
|
585
|
+
// Test sketch
|
|
586
|
+
APP.modules.sketch.init();
|
|
587
|
+
const sketch = APP.modules.sketch.startSketch('XY');
|
|
588
|
+
console.log(sketch);
|
|
589
|
+
|
|
590
|
+
// Test solid
|
|
591
|
+
APP.modules.solid.init();
|
|
592
|
+
const geometry = new THREE.BoxGeometry(10, 10, 10);
|
|
593
|
+
const extrude = APP.modules.solid.extrude(geometry, { distance: 20 });
|
|
594
|
+
console.log(extrude);
|
|
595
|
+
|
|
596
|
+
// Test surface
|
|
597
|
+
APP.modules.surface.init();
|
|
598
|
+
const surf = APP.modules.surface.extrudeSurface(geometry, { distance: 5 });
|
|
599
|
+
console.log(surf);
|
|
600
|
+
|
|
601
|
+
// Test agent API
|
|
602
|
+
window.cycleCAD.execute('sketch', 'startSketch', { plane: 'XY' })
|
|
603
|
+
.then(result => console.log('Agent API works:', result));
|
|
604
|
+
```
|
|
605
|
+
|
|
606
|
+
---
|
|
607
|
+
|
|
608
|
+
All code snippets are production-ready and follow the existing cycleCAD patterns!
|