cyclecad 3.9.4 → 3.9.11
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/CLAUDE.md +165 -1
- package/app/index.html +217 -52
- package/package.json +1 -1
package/CLAUDE.md
CHANGED
|
@@ -953,5 +953,169 @@ rm -f ~/explodeview/.git/index.lock ~/explodeview/.git/HEAD.lock && cd ~/explode
|
|
|
953
953
|
- [ ] Build Photo-to-CAD Reverse Engineering
|
|
954
954
|
- [ ] Build Instant Manufacturability Feedback
|
|
955
955
|
|
|
956
|
+
## Session 2026-04-01 — Critical Bug Fixes + Sketch Wiring + cycleWASH Prospects
|
|
957
|
+
|
|
958
|
+
### Problem Evolution (Chronological)
|
|
959
|
+
1. **cycleWASH prospect spreadsheet** — Built `cycleWASH-NRW-Prospects.xlsx` with 36 leads (bike shops/rentals in NRW), email templates (DE+EN), follow-up tracker. Created with openpyxl, 3 sheets, color-coded priorities.
|
|
960
|
+
2. **TextToCAD syntax error** — `app/js/modules/text-to-cad.js` line 215 had missing `(` after `if` in regex test. Fixed, pushed.
|
|
961
|
+
3. **Splash screen missing** — App launched showing demo geometry (blue box + green cylinder) instead of welcome splash. Built splash with 4 buttons (New Sketch, Open/Import, Text-to-CAD, Inventor Project).
|
|
962
|
+
4. **Splash buttons not responding (3 attempts)** — Root cause: `<script type="module">` creates its own scope. Functions inside cannot be called from inline HTML `onclick`. Solution: regular `<script>` IIFE with `addEventListener` on `id`-based buttons.
|
|
963
|
+
5. **VM mount is copy-on-write** — CRITICAL LESSON: Files edited via Edit tool exist only in VM overlay, NOT on user's Mac. `git status` on Mac shows "nothing to commit". Only reliable delivery: `write_clipboard` → user pastes in Terminal.
|
|
964
|
+
6. **Dialog selectors wrong** — All 12 Tools menu handlers used `.dialog-content` (doesn't exist). Correct selector: `#dialog-body`. Fixed via clipboard Python command.
|
|
965
|
+
7. **Demo geometry removal** — Removed hardcoded `BoxGeometry(60,40,80)` + `CylinderGeometry(20,20,60)`.
|
|
966
|
+
8. **ViewCube click-only** — Only had click-to-snap-to-face. Added drag-to-rotate with pointer events (pointerdown/pointermove/pointerup), spherical coordinate rotation of main camera. Enlarged 90px → 120px.
|
|
967
|
+
9. **Hard Reset button missing** — Added to Help menu (red text). Clears Service Workers, Cache API, localStorage, sessionStorage, IndexedDB. Works in Safari/Chrome/Firefox.
|
|
968
|
+
10. **GitHub Pages CDN cache** — All fixes deployed to GitHub but Pages CDN served stale version. Added `<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">` to prevent future caching.
|
|
969
|
+
11. **Sketch tools not wired** — Sketch menu items (Line/Circle/Rectangle/Arc/Polyline) existed in UI but `handleMenuAction` only showed toasts. `sketch.js` module was never imported. Wired all tools with auto-enter sketch mode on XY plane.
|
|
970
|
+
12. **CRITICAL: Wrong import names killed entire module** — Imported `entitiesToShape` and `getSketchEntities` from `sketch.js`, but actual exports are `entitiesToGeometry` and `getEntities`. This silently crashed the ENTIRE `<script type="module">` block — meaning NO app logic worked (no buttons, no menus, no ViewCube, nothing). Fixed import names.
|
|
971
|
+
|
|
972
|
+
### Key Technical Discoveries
|
|
973
|
+
|
|
974
|
+
**ES Module Silent Failures:**
|
|
975
|
+
When an `import { wrongName } from './module.js'` fails, the entire `<script type="module">` block dies silently — NO console error in Chrome. The page renders HTML/CSS normally but zero JS functionality works. Diagnosis: check `window._scene` (set by module script) — if undefined, module crashed.
|
|
976
|
+
|
|
977
|
+
**How to diagnose:**
|
|
978
|
+
```javascript
|
|
979
|
+
// Dynamic import catches the real error
|
|
980
|
+
import('./js/sketch.js').then(m => console.log(Object.keys(m))).catch(e => console.error(e));
|
|
981
|
+
```
|
|
982
|
+
|
|
983
|
+
**sketch.js actual exports (v0.9.0):**
|
|
984
|
+
`canvasToWorld, clearSketch, endSketch, entitiesToGeometry, getEntities, setGridSize, setSnapEnabled, setTool, startSketch, undo, worldToCanvas`
|
|
985
|
+
|
|
986
|
+
**VM ↔ Mac File Delivery:**
|
|
987
|
+
- Edit tool → VM overlay only (Mac never sees changes)
|
|
988
|
+
- `write_clipboard` → user pastes in Terminal → changes on Mac → git push works
|
|
989
|
+
- Always use Python heredoc scripts for complex multi-line fixes
|
|
990
|
+
- Pattern: `cd ~/cyclecad && python3 << 'PYEOF'\n...\nPYEOF\n&& git add ... && git commit ... && git push`
|
|
991
|
+
|
|
992
|
+
**GitHub Pages Cache:**
|
|
993
|
+
- Raw GitHub (`raw.githubusercontent.com`) updates instantly
|
|
994
|
+
- GitHub Pages CDN (`cyclecad.com`) can lag 5-10 minutes
|
|
995
|
+
- Cache-busting: `?bust=timestamp` in URL forces fresh fetch
|
|
996
|
+
- Meta tags help browser cache but NOT CDN cache
|
|
997
|
+
- Check source of truth: `https://raw.githubusercontent.com/vvlars-cmd/cyclecad/main/app/index.html`
|
|
998
|
+
|
|
999
|
+
### What Was Built/Fixed This Session
|
|
1000
|
+
|
|
1001
|
+
| File | Action | What |
|
|
1002
|
+
|------|--------|------|
|
|
1003
|
+
| `cycleWASH-NRW-Prospects.xlsx` | NEW | 36 prospects, email templates DE+EN, follow-up tracker |
|
|
1004
|
+
| `app/js/modules/text-to-cad.js` | FIXED | Missing `(` after `if` on line 215 |
|
|
1005
|
+
| `app/index.html` | MAJOR | Splash screen, sketch wiring, ViewCube drag, Hard Reset, no-cache meta, dialog selector fixes, demo geometry removal |
|
|
1006
|
+
| `app/js/sketch.js` | EXISTING | Now imported and wired to menu actions |
|
|
1007
|
+
|
|
1008
|
+
### index.html Changes Detail
|
|
1009
|
+
|
|
1010
|
+
**Sketch module import (line ~1447):**
|
|
1011
|
+
```javascript
|
|
1012
|
+
import { startSketch, endSketch, setTool, getEntities, clearSketch, entitiesToGeometry } from './js/sketch.js';
|
|
1013
|
+
```
|
|
1014
|
+
|
|
1015
|
+
**Sketch menu actions wired (in handleMenuAction switch):**
|
|
1016
|
+
- `sketch-new` → `startSketch('XY', camera, controls)`, shows sketch tools toolbar, activates Sketch tab
|
|
1017
|
+
- `sketch-line` → auto-enters sketch mode + `setTool('line')`
|
|
1018
|
+
- `sketch-circle` → auto-enters sketch mode + `setTool('circle')`
|
|
1019
|
+
- `sketch-rectangle` → auto-enters sketch mode + `setTool('rectangle')`
|
|
1020
|
+
- `sketch-arc` → auto-enters sketch mode + `setTool('arc')`
|
|
1021
|
+
- `sketch-polyline` → auto-enters sketch mode + `setTool('polyline')`
|
|
1022
|
+
- `sketch-finish` → `endSketch()`, converts entities to Three.js wireframe, adds to feature tree
|
|
1023
|
+
|
|
1024
|
+
**ViewCube (line ~1558):**
|
|
1025
|
+
- Pointer events for drag-to-rotate (uses THREE.Spherical for orbit)
|
|
1026
|
+
- Click-to-snap still works (detects drag vs click via `vcDragMoved` flag)
|
|
1027
|
+
- 120px size, grab/grabbing cursors, `touchAction: none` for Safari
|
|
1028
|
+
|
|
1029
|
+
**Hard Reset (Help menu):**
|
|
1030
|
+
- `data-action="help-hard-reset"` with `style="color:#ef4444"`
|
|
1031
|
+
- Handler clears: Service Workers, Cache API, localStorage, sessionStorage, IndexedDB
|
|
1032
|
+
- Reloads with `?reset=timestamp` cache buster
|
|
1033
|
+
|
|
1034
|
+
**Workspace tab wiring:**
|
|
1035
|
+
- Clicking "Sketch" tab auto-enters sketch mode
|
|
1036
|
+
- Clicking any other tab auto-finishes sketch and returns to that workspace
|
|
1037
|
+
|
|
1038
|
+
### Bugs Still Present (Known Issues)
|
|
1039
|
+
|
|
1040
|
+
1. **Version badge hardcoded** — Status bar shows `v0.9.0` but npm is at different version. Need to dynamically read from package.json or update on each publish.
|
|
1041
|
+
2. **Sketch drawing untested end-to-end** — Import fix just pushed. Need to verify: click Circle → click center in viewport → drag radius → see circle drawn on 2D canvas overlay.
|
|
1042
|
+
3. **ViewCube not visible sometimes** — The 120px ViewCube renders in top-right of `#viewport-container`. If the container has wrong dimensions or the renderer size doesn't match, it may not show.
|
|
1043
|
+
4. **Three.js scene renders black/empty** — No demo geometry anymore. Until user draws something, viewport shows only grid lines (which may be hard to see on dark background).
|
|
1044
|
+
5. **Safari private window caching** — Even with no-cache meta tags, Safari aggressively caches. Users must use `?bust=xxx` or Cmd+Shift+R.
|
|
1045
|
+
|
|
1046
|
+
### Git State
|
|
1047
|
+
- All changes committed and pushed to `main` branch
|
|
1048
|
+
- Latest commits:
|
|
1049
|
+
- "Fix sketch.js import names (entitiesToShape->entitiesToGeometry)" ← **PENDING USER RUN** (clipboard copied)
|
|
1050
|
+
- "Wire sketch tools (line/circle/rect/arc) + no-cache meta tags"
|
|
1051
|
+
- "Fix ViewCube drag rotation + add Hard Reset button to Help menu"
|
|
1052
|
+
- Various splash screen fixes
|
|
1053
|
+
|
|
1054
|
+
### npm State
|
|
1055
|
+
- **cyclecad**: Last published unknown version. User needs to run `cd ~/cyclecad && npm version patch && npm publish`
|
|
1056
|
+
- **explodeview**: v1.0.18 bumped locally
|
|
1057
|
+
|
|
1058
|
+
### Collaboration Pattern Refinements (This Session)
|
|
1059
|
+
|
|
1060
|
+
| Pattern | Detail |
|
|
1061
|
+
|---------|--------|
|
|
1062
|
+
| **Clipboard delivery** | ALL code changes must go via `write_clipboard` → user pastes in Terminal. VM edits NEVER reach Mac. |
|
|
1063
|
+
| **Python heredoc scripts** | Best format for complex fixes: `python3 << 'PYEOF'\n...\nPYEOF` avoids quoting issues |
|
|
1064
|
+
| **Always verify on GitHub raw** | Before blaming "fix didn't work", check `raw.githubusercontent.com` to confirm push succeeded |
|
|
1065
|
+
| **Module import debugging** | Wrong import names silently kill entire module. Always verify with `import('./file.js').then(m => Object.keys(m))` |
|
|
1066
|
+
| **Cache frustration** | User gets frustrated when fixes are pushed but browser shows old version. Always provide cache-busting URL |
|
|
1067
|
+
| **Short messages = action needed** | "npm" = run npm publish. "done" = command was pasted and run. Don't ask, just provide the command. |
|
|
1068
|
+
| **User tests in Safari private** | Sachin tests in Safari private window. This has the most aggressive caching. Always consider Safari. |
|
|
1069
|
+
|
|
1070
|
+
### Critical Architecture Notes
|
|
1071
|
+
|
|
1072
|
+
**app/index.html structure:**
|
|
1073
|
+
```
|
|
1074
|
+
<head> — meta tags, CSS styles
|
|
1075
|
+
<div id="menu-bar"> — File/Edit/Sketch/Solid/Surface/Assembly/Drawing/Render/Animation/Inspect/Tools/Help menus
|
|
1076
|
+
<div id="container"> — Main layout
|
|
1077
|
+
<div id="viewport-container"> — Three.js canvas + ViewCube
|
|
1078
|
+
<div id="left-panel"> — Model tree / Assembly / Search tabs
|
|
1079
|
+
<div id="right-panel"> — Properties / Parameters / Material tabs
|
|
1080
|
+
<div id="welcome-panel"> — Splash screen (z-index: 9999)
|
|
1081
|
+
<script> IIFE — Splash button wiring (MUST be regular script, NOT module)
|
|
1082
|
+
<div id="dialog-overlay"> — Modal dialogs (z-index: 10000)
|
|
1083
|
+
<script type="module"> — ALL app logic:
|
|
1084
|
+
- Three.js imports + scene setup
|
|
1085
|
+
- sketch.js import
|
|
1086
|
+
- killer-features.js import
|
|
1087
|
+
- Camera, renderer, lights, grid
|
|
1088
|
+
- ViewCube (separate scene + renderer)
|
|
1089
|
+
- Animation loop
|
|
1090
|
+
- handleMenuAction() switch — ALL menu/toolbar actions
|
|
1091
|
+
- Workspace tab switching
|
|
1092
|
+
- Keyboard shortcuts
|
|
1093
|
+
- Event delegation for menu/toolbar clicks
|
|
1094
|
+
```
|
|
1095
|
+
|
|
1096
|
+
**z-index hierarchy:**
|
|
1097
|
+
- `dialog-overlay`: 10000
|
|
1098
|
+
- `welcome-panel`: 9999
|
|
1099
|
+
- `toast-container`: 9999
|
|
1100
|
+
- ViewCube: 100
|
|
1101
|
+
- Sketch canvas: 30
|
|
1102
|
+
|
|
1103
|
+
### Pending Tasks (Updated 2026-04-01)
|
|
1104
|
+
- [ ] **IMMEDIATE**: User needs to paste clipboard command fixing import names (entitiesToShape→entitiesToGeometry)
|
|
1105
|
+
- [ ] npm publish (user runs `cd ~/cyclecad && npm version patch && npm publish`)
|
|
1106
|
+
- [ ] Verify sketch circle drawing works end-to-end after import fix
|
|
1107
|
+
- [ ] Test ViewCube drag in Safari
|
|
1108
|
+
- [ ] Test Hard Reset button in Safari
|
|
1109
|
+
- [ ] Update version badge to read dynamically from package.json
|
|
1110
|
+
- [ ] Wire splash "New Sketch" button to actually trigger sketch-new action (currently only dismisses)
|
|
1111
|
+
- [ ] Wire splash "Open/Import" button to trigger file-import action
|
|
1112
|
+
- [ ] Wire splash "Text-to-CAD" button to trigger text-to-cad dialog
|
|
1113
|
+
- [ ] Wire splash "Inventor Project" button to trigger inventor import
|
|
1114
|
+
- [ ] ExplodeView route redirects push
|
|
1115
|
+
- [ ] Run test agents in Chrome and fix failures
|
|
1116
|
+
- [ ] Test STEP import with OpenCascade.js WASM
|
|
1117
|
+
- [ ] Build Text-to-CAD with Live Preview
|
|
1118
|
+
- [ ] Build Photo-to-CAD Reverse Engineering
|
|
1119
|
+
|
|
956
1120
|
# currentDate
|
|
957
|
-
Today's date is 2026-
|
|
1121
|
+
Today's date is 2026-04-01.
|
package/app/index.html
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
<!DOCTYPE html>
|
|
2
2
|
<html lang="en">
|
|
3
3
|
<head>
|
|
4
|
+
<meta http-equiv="Cache-Control" content="no-cache, no-store, must-revalidate">
|
|
5
|
+
<meta http-equiv="Pragma" content="no-cache">
|
|
6
|
+
<meta http-equiv="Expires" content="0">
|
|
4
7
|
<meta charset="UTF-8">
|
|
5
8
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
6
9
|
<title>cycleCAD - Fusion 360 Clone - Parametric 3D CAD Modeler</title>
|
|
@@ -989,6 +992,8 @@
|
|
|
989
992
|
<button class="menu-item-link" data-action="help-docs">Documentation</button>
|
|
990
993
|
<button class="menu-item-link" data-action="help-shortcuts">Keyboard Shortcuts (?)</button>
|
|
991
994
|
<button class="menu-item-link" data-action="help-about">About cycleCAD</button>
|
|
995
|
+
<div style="border-top:1px solid #444;margin:4px 0;"></div>
|
|
996
|
+
<button class="menu-item-link" data-action="help-hard-reset" style="color:#ef4444;">Hard Reset (Clear Cache)</button>
|
|
992
997
|
</div>
|
|
993
998
|
</div>
|
|
994
999
|
</div>
|
|
@@ -1148,7 +1153,7 @@
|
|
|
1148
1153
|
<div id="viewport-container" style="position:relative;">
|
|
1149
1154
|
<canvas id="viewport"></canvas>
|
|
1150
1155
|
<!-- ViewCube -->
|
|
1151
|
-
<div id="viewcube" style="position:absolute;top:12px;right:12px;width:
|
|
1156
|
+
<div id="viewcube" style="position:absolute;top:12px;right:12px;width:120px;height:120px;pointer-events:auto;z-index:100;"></div>
|
|
1152
1157
|
</div>
|
|
1153
1158
|
|
|
1154
1159
|
<!-- Right Panel (Properties) -->
|
|
@@ -1308,38 +1313,6 @@
|
|
|
1308
1313
|
|
|
1309
1314
|
</div>
|
|
1310
1315
|
|
|
1311
|
-
<!-- Welcome Splash Screen -->
|
|
1312
|
-
<div id="welcome-panel" style="position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.75);display:flex;align-items:center;justify-content:center;z-index:9999;">
|
|
1313
|
-
<div style="background:#252526;border:1px solid #3c3c3c;border-radius:12px;padding:40px 48px;max-width:560px;width:90%;text-align:center;box-shadow:0 20px 60px rgba(0,0,0,0.5);">
|
|
1314
|
-
<div style="font-size:36px;margin-bottom:4px;">
|
|
1315
|
-
<span style="color:#0284C7;font-weight:700;">cycle</span><span style="color:#e0e0e0;font-weight:300;">CAD</span>
|
|
1316
|
-
</div>
|
|
1317
|
-
<div style="color:#888;font-size:13px;margin-bottom:28px;">Agent-First Parametric 3D CAD Modeler</div>
|
|
1318
|
-
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:20px;">
|
|
1319
|
-
<button onclick="window._dismissSplash('sketch')" style="background:#0284C7;color:#fff;border:none;border-radius:8px;padding:18px 16px;cursor:pointer;font-size:14px;font-weight:600;">
|
|
1320
|
-
<div style="font-size:24px;margin-bottom:6px;">✏️</div>
|
|
1321
|
-
New Sketch
|
|
1322
|
-
<div style="font-size:11px;font-weight:400;color:rgba(255,255,255,0.7);margin-top:4px;">Start with a 2D sketch</div>
|
|
1323
|
-
</button>
|
|
1324
|
-
<button onclick="window._dismissSplash('import')" style="background:#374151;color:#fff;border:1px solid #4b5563;border-radius:8px;padding:18px 16px;cursor:pointer;font-size:14px;font-weight:600;">
|
|
1325
|
-
<div style="font-size:24px;margin-bottom:6px;">📂</div>
|
|
1326
|
-
Open / Import
|
|
1327
|
-
<div style="font-size:11px;font-weight:400;color:rgba(255,255,255,0.7);margin-top:4px;">STEP, STL, Inventor, JSON</div>
|
|
1328
|
-
</button>
|
|
1329
|
-
<button onclick="window._dismissSplash('textcad')" style="background:#374151;color:#fff;border:1px solid #4b5563;border-radius:8px;padding:18px 16px;cursor:pointer;font-size:14px;font-weight:600;">
|
|
1330
|
-
<div style="font-size:24px;margin-bottom:6px;">🤖</div>
|
|
1331
|
-
Text-to-CAD
|
|
1332
|
-
<div style="font-size:11px;font-weight:400;color:rgba(255,255,255,0.7);margin-top:4px;">Describe a part in English</div>
|
|
1333
|
-
</button>
|
|
1334
|
-
<button onclick="window._dismissSplash('inventor')" style="background:#374151;color:#fff;border:1px solid #4b5563;border-radius:8px;padding:18px 16px;cursor:pointer;font-size:14px;font-weight:600;">
|
|
1335
|
-
<div style="font-size:24px;margin-bottom:6px;">🏭</div>
|
|
1336
|
-
Inventor Project
|
|
1337
|
-
<div style="font-size:11px;font-weight:400;color:rgba(255,255,255,0.7);margin-top:4px;">Load .ipj / .ipt / .iam</div>
|
|
1338
|
-
</button>
|
|
1339
|
-
</div>
|
|
1340
|
-
<div style="color:#666;font-size:11px;"><span id="splash-version">v0.9.0</span> · 12 killer features · 46 modules · <a href="https://github.com/vvlars-cmd/cyclecad" target="_blank" style="color:#0284C7;text-decoration:none;">GitHub</a></div>
|
|
1341
|
-
</div>
|
|
1342
|
-
</div>
|
|
1343
1316
|
<script>
|
|
1344
1317
|
window._dismissSplash = function(action) {
|
|
1345
1318
|
// Update splash version from status bar
|
|
@@ -1358,6 +1331,30 @@ window._dismissSplash = function(action) {
|
|
|
1358
1331
|
};
|
|
1359
1332
|
</script>
|
|
1360
1333
|
|
|
1334
|
+
<!-- Welcome Splash Screen -->
|
|
1335
|
+
<div id="welcome-panel" style="position:fixed;top:0;left:0;right:0;bottom:0;background:rgba(0,0,0,0.75);display:flex;align-items:center;justify-content:center;z-index:9999;">
|
|
1336
|
+
<div style="background:#252526;border:1px solid #3c3c3c;border-radius:12px;padding:40px 48px;max-width:560px;width:90%;text-align:center;box-shadow:0 20px 60px rgba(0,0,0,0.5);">
|
|
1337
|
+
<div style="font-size:36px;margin-bottom:4px;"><span style="color:#0284C7;font-weight:700;">cycle</span><span style="color:#e0e0e0;font-weight:300;">CAD</span></div>
|
|
1338
|
+
<div style="color:#888;font-size:13px;margin-bottom:28px;">Agent-First Parametric 3D CAD Modeler</div>
|
|
1339
|
+
<div style="display:grid;grid-template-columns:1fr 1fr;gap:12px;margin-bottom:20px;">
|
|
1340
|
+
<button id="splash-sketch" style="background:#0284C7;color:#fff;border:none;border-radius:8px;padding:18px 16px;cursor:pointer;font-size:14px;font-weight:600;"><div style="font-size:24px;margin-bottom:6px;">✏️</div>New Sketch<div style="font-size:11px;font-weight:400;color:rgba(255,255,255,0.7);margin-top:4px;">Start with a 2D sketch</div></button>
|
|
1341
|
+
<button id="splash-import" style="background:#374151;color:#fff;border:1px solid #4b5563;border-radius:8px;padding:18px 16px;cursor:pointer;font-size:14px;font-weight:600;"><div style="font-size:24px;margin-bottom:6px;">📂</div>Open / Import<div style="font-size:11px;font-weight:400;color:rgba(255,255,255,0.7);margin-top:4px;">STEP, STL, Inventor, JSON</div></button>
|
|
1342
|
+
<button id="splash-textcad" style="background:#374151;color:#fff;border:1px solid #4b5563;border-radius:8px;padding:18px 16px;cursor:pointer;font-size:14px;font-weight:600;"><div style="font-size:24px;margin-bottom:6px;">🤖</div>Text-to-CAD<div style="font-size:11px;font-weight:400;color:rgba(255,255,255,0.7);margin-top:4px;">Describe a part in English</div></button>
|
|
1343
|
+
<button id="splash-inventor" style="background:#374151;color:#fff;border:1px solid #4b5563;border-radius:8px;padding:18px 16px;cursor:pointer;font-size:14px;font-weight:600;"><div style="font-size:24px;margin-bottom:6px;">🏭</div>Inventor Project<div style="font-size:11px;font-weight:400;color:rgba(255,255,255,0.7);margin-top:4px;">Load .ipj / .ipt / .iam</div></button>
|
|
1344
|
+
</div>
|
|
1345
|
+
<div style="color:#666;font-size:11px;">12 killer features · 46 modules · <a href="https://github.com/vvlars-cmd/cyclecad" target="_blank" style="color:#0284C7;text-decoration:none;">GitHub</a></div>
|
|
1346
|
+
</div>
|
|
1347
|
+
</div>
|
|
1348
|
+
<script>
|
|
1349
|
+
(function() {
|
|
1350
|
+
function dismiss() { document.getElementById("welcome-panel").style.display = "none"; }
|
|
1351
|
+
document.getElementById("splash-sketch").addEventListener("click", dismiss);
|
|
1352
|
+
document.getElementById("splash-import").addEventListener("click", dismiss);
|
|
1353
|
+
document.getElementById("splash-textcad").addEventListener("click", dismiss);
|
|
1354
|
+
document.getElementById("splash-inventor").addEventListener("click", dismiss);
|
|
1355
|
+
})();
|
|
1356
|
+
</script>
|
|
1357
|
+
|
|
1361
1358
|
<!-- Modal Dialogs -->
|
|
1362
1359
|
<div id="dialog-overlay" class="modal-overlay">
|
|
1363
1360
|
<div class="modal-dialog">
|
|
@@ -1451,6 +1448,7 @@ window._dismissSplash = function(action) {
|
|
|
1451
1448
|
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
|
|
1452
1449
|
import { GridHelper } from 'three';
|
|
1453
1450
|
import { KillerFeatures } from './js/killer-features.js';
|
|
1451
|
+
import { startSketch, endSketch, setTool, getEntities, clearSketch, entitiesToGeometry } from './js/sketch.js';
|
|
1454
1452
|
|
|
1455
1453
|
// ===== Three.js Viewport Setup =====
|
|
1456
1454
|
const scene = new THREE.Scene();
|
|
@@ -1517,7 +1515,7 @@ window._dismissSplash = function(action) {
|
|
|
1517
1515
|
const vcCamera = new THREE.PerspectiveCamera(40, 1, 0.1, 100);
|
|
1518
1516
|
vcCamera.position.set(0, 0, 3.5);
|
|
1519
1517
|
const vcRenderer = new THREE.WebGLRenderer({ alpha: true, antialias: true });
|
|
1520
|
-
vcRenderer.setSize(
|
|
1518
|
+
vcRenderer.setSize(120, 120);
|
|
1521
1519
|
vcRenderer.setPixelRatio(window.devicePixelRatio);
|
|
1522
1520
|
vcContainer.appendChild(vcRenderer.domElement);
|
|
1523
1521
|
|
|
@@ -1563,26 +1561,63 @@ window._dismissSplash = function(action) {
|
|
|
1563
1561
|
};
|
|
1564
1562
|
const vcRay = new THREE.Raycaster();
|
|
1565
1563
|
const vcMouse = new THREE.Vector2();
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
|
|
1577
|
-
|
|
1578
|
-
|
|
1579
|
-
|
|
1580
|
-
|
|
1581
|
-
|
|
1564
|
+
// ViewCube drag-to-rotate + click-to-snap
|
|
1565
|
+
let vcDragging = false, vcDragStart = null, vcDragMoved = false;
|
|
1566
|
+
const vcEl = vcRenderer.domElement;
|
|
1567
|
+
vcEl.addEventListener('pointerdown', (e) => {
|
|
1568
|
+
vcDragging = true; vcDragMoved = false;
|
|
1569
|
+
vcDragStart = { x: e.clientX, y: e.clientY };
|
|
1570
|
+
vcEl.setPointerCapture(e.pointerId);
|
|
1571
|
+
e.preventDefault(); e.stopPropagation();
|
|
1572
|
+
});
|
|
1573
|
+
vcEl.addEventListener('pointermove', (e) => {
|
|
1574
|
+
if (!vcDragging || !vcDragStart) return;
|
|
1575
|
+
const dx = e.clientX - vcDragStart.x;
|
|
1576
|
+
const dy = e.clientY - vcDragStart.y;
|
|
1577
|
+
if (Math.abs(dx) > 2 || Math.abs(dy) > 2) vcDragMoved = true;
|
|
1578
|
+
if (!vcDragMoved) return;
|
|
1579
|
+
const speed = 0.01;
|
|
1580
|
+
const spherical = new THREE.Spherical().setFromVector3(
|
|
1581
|
+
camera.position.clone().sub(controls.target)
|
|
1582
|
+
);
|
|
1583
|
+
spherical.theta -= dx * speed;
|
|
1584
|
+
spherical.phi -= dy * speed;
|
|
1585
|
+
spherical.phi = Math.max(0.05, Math.min(Math.PI - 0.05, spherical.phi));
|
|
1586
|
+
camera.position.copy(
|
|
1587
|
+
new THREE.Vector3().setFromSpherical(spherical).add(controls.target)
|
|
1588
|
+
);
|
|
1589
|
+
camera.lookAt(controls.target);
|
|
1590
|
+
controls.update();
|
|
1591
|
+
vcDragStart = { x: e.clientX, y: e.clientY };
|
|
1592
|
+
e.preventDefault(); e.stopPropagation();
|
|
1593
|
+
});
|
|
1594
|
+
vcEl.addEventListener('pointerup', (e) => {
|
|
1595
|
+
if (vcDragging && !vcDragMoved) {
|
|
1596
|
+
const rect = vcEl.getBoundingClientRect();
|
|
1597
|
+
vcMouse.x = ((e.clientX - rect.left) / rect.width) * 2 - 1;
|
|
1598
|
+
vcMouse.y = -((e.clientY - rect.top) / rect.height) * 2 + 1;
|
|
1599
|
+
vcRay.setFromCamera(vcMouse, vcCamera);
|
|
1600
|
+
const hits = vcRay.intersectObject(vcCube);
|
|
1601
|
+
if (hits.length > 0) {
|
|
1602
|
+
const fi = hits[0].face.materialIndex;
|
|
1603
|
+
const label = faceLabels[fi];
|
|
1604
|
+
const v = vcViews[label];
|
|
1605
|
+
if (v) {
|
|
1606
|
+
const dist = camera.position.length();
|
|
1607
|
+
const s = dist / 3;
|
|
1608
|
+
camera.position.set(v.x * s, v.y * s, v.z * s);
|
|
1609
|
+
camera.lookAt(controls.target);
|
|
1610
|
+
controls.update();
|
|
1611
|
+
}
|
|
1582
1612
|
}
|
|
1583
1613
|
}
|
|
1614
|
+
vcDragging = false; vcDragStart = null; vcDragMoved = false;
|
|
1615
|
+
e.preventDefault(); e.stopPropagation();
|
|
1584
1616
|
});
|
|
1585
|
-
|
|
1617
|
+
vcEl.style.cursor = 'grab';
|
|
1618
|
+
vcEl.addEventListener('pointerdown', () => { vcEl.style.cursor = 'grabbing'; });
|
|
1619
|
+
vcEl.addEventListener('pointerup', () => { vcEl.style.cursor = 'grab'; });
|
|
1620
|
+
vcEl.style.touchAction = 'none';
|
|
1586
1621
|
|
|
1587
1622
|
// Animation loop
|
|
1588
1623
|
function animate() {
|
|
@@ -1619,6 +1654,23 @@ window._dismissSplash = function(action) {
|
|
|
1619
1654
|
// ===== DOM Queries =====
|
|
1620
1655
|
const menuBar = document.getElementById('menu-bar');
|
|
1621
1656
|
const workspaceTabs = document.querySelectorAll('.workspace-tab');
|
|
1657
|
+
// Wire workspace tabs to enter/exit sketch mode
|
|
1658
|
+
workspaceTabs.forEach(tab => {
|
|
1659
|
+
tab.addEventListener('click', () => {
|
|
1660
|
+
const ws = tab.getAttribute('data-workspace');
|
|
1661
|
+
workspaceTabs.forEach(t => t.classList.remove('active'));
|
|
1662
|
+
tab.classList.add('active');
|
|
1663
|
+
// Show/hide workspace-specific toolbars
|
|
1664
|
+
document.querySelectorAll('.workspace-tools').forEach(t => t.style.display = 'none');
|
|
1665
|
+
const wsTools = document.getElementById(ws + '-tools');
|
|
1666
|
+
if (wsTools) wsTools.style.display = 'flex';
|
|
1667
|
+
if (ws === 'sketch' && !appState.isSketchMode) {
|
|
1668
|
+
handleMenuAction('sketch-new');
|
|
1669
|
+
} else if (ws !== 'sketch' && appState.isSketchMode) {
|
|
1670
|
+
handleMenuAction('sketch-finish');
|
|
1671
|
+
}
|
|
1672
|
+
});
|
|
1673
|
+
});
|
|
1622
1674
|
const leftPanelTabs = document.querySelectorAll('.left-panel-tab');
|
|
1623
1675
|
const rightPanelTabs = document.querySelectorAll('.right-panel-tab');
|
|
1624
1676
|
const viewportContainer = document.getElementById('viewport-container');
|
|
@@ -1653,8 +1705,98 @@ window._dismissSplash = function(action) {
|
|
|
1653
1705
|
case 'edit-redo':
|
|
1654
1706
|
showToast('Redo', 'success');
|
|
1655
1707
|
break;
|
|
1708
|
+
case 'sketch-new':
|
|
1709
|
+
if (!appState.isSketchMode) {
|
|
1710
|
+
appState.isSketchMode = true;
|
|
1711
|
+
startSketch('XY', camera, controls);
|
|
1712
|
+
showToast('Sketch mode — draw on XY plane', 'success');
|
|
1713
|
+
// Show sketch tools, activate Sketch tab
|
|
1714
|
+
var st = document.getElementById('sketch-tools');
|
|
1715
|
+
if (st) st.style.display = 'flex';
|
|
1716
|
+
document.querySelectorAll('.workspace-tab').forEach(t => t.classList.remove('active'));
|
|
1717
|
+
var skTab = document.querySelector('[data-workspace="sketch"]');
|
|
1718
|
+
if (skTab) skTab.classList.add('active');
|
|
1719
|
+
}
|
|
1720
|
+
break;
|
|
1656
1721
|
case 'sketch-line':
|
|
1657
|
-
if (appState.isSketchMode)
|
|
1722
|
+
if (!appState.isSketchMode) { handleMenuAction('sketch-new'); }
|
|
1723
|
+
setTool('line');
|
|
1724
|
+
showToast('Line tool — click to place points', 'success');
|
|
1725
|
+
break;
|
|
1726
|
+
case 'sketch-rectangle':
|
|
1727
|
+
if (!appState.isSketchMode) { handleMenuAction('sketch-new'); }
|
|
1728
|
+
setTool('rectangle');
|
|
1729
|
+
showToast('Rectangle tool — click two corners', 'success');
|
|
1730
|
+
break;
|
|
1731
|
+
case 'sketch-circle':
|
|
1732
|
+
if (!appState.isSketchMode) { handleMenuAction('sketch-new'); }
|
|
1733
|
+
setTool('circle');
|
|
1734
|
+
showToast('Circle tool — click center, then radius', 'success');
|
|
1735
|
+
break;
|
|
1736
|
+
case 'sketch-arc':
|
|
1737
|
+
if (!appState.isSketchMode) { handleMenuAction('sketch-new'); }
|
|
1738
|
+
setTool('arc');
|
|
1739
|
+
showToast('Arc tool — click 3 points', 'success');
|
|
1740
|
+
break;
|
|
1741
|
+
case 'sketch-polyline':
|
|
1742
|
+
if (!appState.isSketchMode) { handleMenuAction('sketch-new'); }
|
|
1743
|
+
setTool('polyline');
|
|
1744
|
+
showToast('Polyline tool — click points, double-click to finish', 'success');
|
|
1745
|
+
break;
|
|
1746
|
+
case 'sketch-finish':
|
|
1747
|
+
if (appState.isSketchMode) {
|
|
1748
|
+
const entities = endSketch();
|
|
1749
|
+
appState.isSketchMode = false;
|
|
1750
|
+
// Hide sketch tools, back to Design tab
|
|
1751
|
+
var st2 = document.getElementById('sketch-tools');
|
|
1752
|
+
if (st2) st2.style.display = 'none';
|
|
1753
|
+
document.querySelectorAll('.workspace-tab').forEach(t => t.classList.remove('active'));
|
|
1754
|
+
var dTab = document.querySelector('[data-workspace="design"]');
|
|
1755
|
+
if (dTab) dTab.classList.add('active');
|
|
1756
|
+
if (entities.length > 0) {
|
|
1757
|
+
// Convert sketch entities to 3D wireframe in scene
|
|
1758
|
+
try {
|
|
1759
|
+
const shape = entitiesToGeometry(entities);
|
|
1760
|
+
if (shape) {
|
|
1761
|
+
const mat = new THREE.LineBasicMaterial({ color: 0x00ff00 });
|
|
1762
|
+
const edges = new THREE.EdgesGeometry(shape);
|
|
1763
|
+
const wireframe = new THREE.LineSegments(edges, mat);
|
|
1764
|
+
wireframe.name = 'Sketch' + (appState.featureTree.length + 1);
|
|
1765
|
+
scene.add(wireframe);
|
|
1766
|
+
appState.featureTree.push({ name: wireframe.name, type: 'Sketch', visible: true, mesh: wireframe });
|
|
1767
|
+
showToast('Sketch finished — ' + entities.length + ' entities', 'success');
|
|
1768
|
+
} else {
|
|
1769
|
+
// Just add lines directly
|
|
1770
|
+
const lineMat = new THREE.LineBasicMaterial({ color: 0x00ccff });
|
|
1771
|
+
entities.forEach((ent, idx) => {
|
|
1772
|
+
if (ent.points && ent.points.length >= 2) {
|
|
1773
|
+
const pts = ent.points.map(p => new THREE.Vector3(p.x, p.y, 0));
|
|
1774
|
+
if (ent.type === 'circle' && ent.center && ent.radius) {
|
|
1775
|
+
const curve = new THREE.EllipseCurve(ent.center.x, ent.center.y, ent.radius, ent.radius, 0, Math.PI * 2, false, 0);
|
|
1776
|
+
const cPts = curve.getPoints(64).map(p => new THREE.Vector3(p.x, p.y, 0));
|
|
1777
|
+
const geo = new THREE.BufferGeometry().setFromPoints(cPts);
|
|
1778
|
+
const line = new THREE.Line(geo, lineMat);
|
|
1779
|
+
line.name = 'SketchCircle' + (idx + 1);
|
|
1780
|
+
scene.add(line);
|
|
1781
|
+
} else {
|
|
1782
|
+
const geo = new THREE.BufferGeometry().setFromPoints(pts);
|
|
1783
|
+
const line = new THREE.Line(geo, lineMat);
|
|
1784
|
+
line.name = 'SketchLine' + (idx + 1);
|
|
1785
|
+
scene.add(line);
|
|
1786
|
+
}
|
|
1787
|
+
}
|
|
1788
|
+
});
|
|
1789
|
+
appState.featureTree.push({ name: 'Sketch' + (appState.featureTree.length + 1), type: 'Sketch', visible: true });
|
|
1790
|
+
showToast('Sketch finished — ' + entities.length + ' entities added', 'success');
|
|
1791
|
+
}
|
|
1792
|
+
} catch(e) {
|
|
1793
|
+
console.warn('Sketch to shape error:', e);
|
|
1794
|
+
showToast('Sketch finished (wireframe only)', 'warning');
|
|
1795
|
+
}
|
|
1796
|
+
} else {
|
|
1797
|
+
showToast('Empty sketch discarded', 'warning');
|
|
1798
|
+
}
|
|
1799
|
+
}
|
|
1658
1800
|
break;
|
|
1659
1801
|
case 'solid-extrude':
|
|
1660
1802
|
showToast('Extrude tool active', 'success');
|
|
@@ -1671,6 +1813,29 @@ window._dismissSplash = function(action) {
|
|
|
1671
1813
|
case 'help-docs':
|
|
1672
1814
|
window.open('https://cyclecad.com/docs', '_blank');
|
|
1673
1815
|
break;
|
|
1816
|
+
case 'help-hard-reset':
|
|
1817
|
+
if (confirm('This will clear ALL cached data and reload. Continue?')) {
|
|
1818
|
+
(async () => {
|
|
1819
|
+
try {
|
|
1820
|
+
if ('serviceWorker' in navigator) {
|
|
1821
|
+
const regs = await navigator.serviceWorker.getRegistrations();
|
|
1822
|
+
for (const r of regs) await r.unregister();
|
|
1823
|
+
}
|
|
1824
|
+
if ('caches' in window) {
|
|
1825
|
+
const keys = await caches.keys();
|
|
1826
|
+
for (const k of keys) await caches.delete(k);
|
|
1827
|
+
}
|
|
1828
|
+
try { localStorage.clear(); } catch(e) {}
|
|
1829
|
+
try { sessionStorage.clear(); } catch(e) {}
|
|
1830
|
+
if (indexedDB.databases) {
|
|
1831
|
+
const dbs = await indexedDB.databases();
|
|
1832
|
+
for (const db of dbs) indexedDB.deleteDatabase(db.name);
|
|
1833
|
+
}
|
|
1834
|
+
window.location.href = window.location.pathname + '?reset=' + Date.now();
|
|
1835
|
+
} catch(e) { window.location.reload(true); }
|
|
1836
|
+
})();
|
|
1837
|
+
}
|
|
1838
|
+
break;
|
|
1674
1839
|
case 'help-about':
|
|
1675
1840
|
showDialog('About cycleCAD', 'cycleCAD v0.9.0 - Fusion 360 Clone<br>Open-source parametric 3D CAD modeler<br><br>Built with Three.js, supporting STEP/IGES import, full parametric modeling, and AI-powered design assistance.');
|
|
1676
1841
|
break;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "cyclecad",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.11",
|
|
4
4
|
"description": "Browser-based parametric 3D CAD modeler with AI-powered tools, native Inventor file parsing, and smart assembly management. No install required.",
|
|
5
5
|
"main": "index.html",
|
|
6
6
|
"bin": {
|