cyclecad 3.0.0 → 3.2.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.
Files changed (67) hide show
  1. package/BILLING-IMPLEMENTATION-SUMMARY.md +425 -0
  2. package/BILLING-INDEX.md +293 -0
  3. package/BILLING-INTEGRATION-GUIDE.md +414 -0
  4. package/COLLABORATION-INDEX.md +440 -0
  5. package/COLLABORATION-SYSTEM-SUMMARY.md +548 -0
  6. package/DOCKER-BUILD-MANIFEST.txt +483 -0
  7. package/DOCKER-FILES-REFERENCE.md +440 -0
  8. package/DOCKER-INFRASTRUCTURE.md +475 -0
  9. package/DOCKER-README.md +435 -0
  10. package/Dockerfile +33 -55
  11. package/PWA-FILES-CREATED.txt +350 -0
  12. package/QUICK-START-TESTING.md +126 -0
  13. package/STEP-IMPORT-QUICKSTART.md +347 -0
  14. package/STEP-IMPORT-SYSTEM-SUMMARY.md +502 -0
  15. package/app/css/mobile.css +1074 -0
  16. package/app/icons/generate-icons.js +203 -0
  17. package/app/index.html +93 -0
  18. package/app/js/billing-ui.js +990 -0
  19. package/app/js/brep-kernel.js +933 -981
  20. package/app/js/collab-client.js +750 -0
  21. package/app/js/mobile-nav.js +623 -0
  22. package/app/js/mobile-toolbar.js +476 -0
  23. package/app/js/modules/billing-module.js +724 -0
  24. package/app/js/modules/step-module-enhanced.js +938 -0
  25. package/app/js/offline-manager.js +705 -0
  26. package/app/js/responsive-init.js +360 -0
  27. package/app/js/touch-handler.js +429 -0
  28. package/app/manifest.json +211 -0
  29. package/app/offline.html +508 -0
  30. package/app/sw.js +571 -0
  31. package/app/tests/billing-tests.html +779 -0
  32. package/app/tests/brep-tests.html +980 -0
  33. package/app/tests/collab-tests.html +743 -0
  34. package/app/tests/mobile-tests.html +1299 -0
  35. package/app/tests/pwa-tests.html +1134 -0
  36. package/app/tests/step-tests.html +1042 -0
  37. package/app/tests/test-agent-v3.html +719 -0
  38. package/docker-compose.yml +225 -0
  39. package/docs/BILLING-HELP.json +260 -0
  40. package/docs/BILLING-README.md +639 -0
  41. package/docs/BILLING-TUTORIAL.md +736 -0
  42. package/docs/BREP-HELP.json +326 -0
  43. package/docs/BREP-TUTORIAL.md +802 -0
  44. package/docs/COLLABORATION-HELP.json +228 -0
  45. package/docs/COLLABORATION-TUTORIAL.md +818 -0
  46. package/docs/DOCKER-HELP.json +224 -0
  47. package/docs/DOCKER-TUTORIAL.md +974 -0
  48. package/docs/MOBILE-HELP.json +243 -0
  49. package/docs/MOBILE-RESPONSIVE-README.md +378 -0
  50. package/docs/MOBILE-TUTORIAL.md +747 -0
  51. package/docs/PWA-HELP.json +228 -0
  52. package/docs/PWA-README.md +662 -0
  53. package/docs/PWA-TUTORIAL.md +757 -0
  54. package/docs/STEP-HELP.json +481 -0
  55. package/docs/STEP-IMPORT-TUTORIAL.md +824 -0
  56. package/docs/TESTING-GUIDE.md +528 -0
  57. package/docs/TESTING-HELP.json +182 -0
  58. package/fusion-vs-cyclecad.html +1771 -0
  59. package/nginx.conf +237 -0
  60. package/package.json +1 -1
  61. package/server/Dockerfile.converter +51 -0
  62. package/server/Dockerfile.signaling +28 -0
  63. package/server/billing-server.js +487 -0
  64. package/server/converter-enhanced.py +528 -0
  65. package/server/requirements-converter.txt +29 -0
  66. package/server/signaling-server.js +801 -0
  67. package/tests/docker-tests.sh +389 -0
@@ -0,0 +1,203 @@
1
+ #!/usr/bin/env node
2
+
3
+ /**
4
+ * cycleCAD PWA Icon Generator
5
+ * Generates all required PWA icon sizes from SVG source
6
+ *
7
+ * Usage:
8
+ * node generate-icons.js [--source icon.svg] [--output ./icons]
9
+ *
10
+ * Requires: sharp or canvas package
11
+ */
12
+
13
+ const fs = require('fs');
14
+ const path = require('path');
15
+
16
+ // Icon sizes and purposes
17
+ const ICON_SIZES = [
18
+ { size: 72, purpose: 'any' },
19
+ { size: 96, purpose: 'any' },
20
+ { size: 128, purpose: 'any' },
21
+ { size: 144, purpose: 'any' },
22
+ { size: 152, purpose: 'any' },
23
+ { size: 192, purpose: 'any' },
24
+ { size: 384, purpose: 'any' },
25
+ { size: 512, purpose: 'any' },
26
+ { size: 192, purpose: 'maskable' },
27
+ { size: 512, purpose: 'maskable' }
28
+ ];
29
+
30
+ // Screenshot sizes
31
+ const SCREENSHOT_SIZES = [
32
+ { width: 540, height: 720, type: 'narrow' },
33
+ { width: 1280, height: 720, type: 'wide' }
34
+ ];
35
+
36
+ // Shortcut icon sizes
37
+ const SHORTCUT_SIZES = [
38
+ { size: 192, name: 'new' },
39
+ { size: 192, name: 'open' },
40
+ { size: 192, name: 'import' }
41
+ ];
42
+
43
+ /**
44
+ * Generate SVG source icon
45
+ * Creates a blue gear/CAD logo in SVG format
46
+ */
47
+ function generateSourceSVG() {
48
+ const svgContent = `<?xml version="1.0" encoding="UTF-8"?>
49
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512" width="512" height="512">
50
+ <!-- Background -->
51
+ <rect width="512" height="512" fill="#0284C7" rx="100"/>
52
+
53
+ <!-- Gear shape representing CAD/design -->
54
+ <g transform="translate(256, 256)">
55
+ <!-- Outer gear teeth -->
56
+ <circle cx="0" cy="-80" r="25" fill="#ffffff"/>
57
+ <circle cx="57" cy="-57" r="25" fill="#ffffff"/>
58
+ <circle cx="80" cy="0" r="25" fill="#ffffff"/>
59
+ <circle cx="57" cy="57" r="25" fill="#ffffff"/>
60
+ <circle cx="0" cy="80" r="25" fill="#ffffff"/>
61
+ <circle cx="-57" cy="57" r="25" fill="#ffffff"/>
62
+ <circle cx="-80" cy="0" r="25" fill="#ffffff"/>
63
+ <circle cx="-57" cy="-57" r="25" fill="#ffffff"/>
64
+
65
+ <!-- Inner gear body -->
66
+ <circle cx="0" cy="0" r="60" fill="#ffffff"/>
67
+
68
+ <!-- Center hub -->
69
+ <circle cx="0" cy="0" r="30" fill="#0284C7"/>
70
+ </g>
71
+
72
+ <!-- 3D cube wireframe overlay (subtle) -->
73
+ <g transform="translate(256, 256)" opacity="0.3">
74
+ <polyline points="-40,-40 40,-40 40,40 -40,40 -40,-40" stroke="#ffffff" stroke-width="3" fill="none"/>
75
+ <polyline points="-30,-30 30,-30 30,30 -30,30 -30,-30" stroke="#ffffff" stroke-width="2" fill="none" transform="translate(10, 10)"/>
76
+ <line x1="-40" y1="-40" x2="-30" y2="-30" stroke="#ffffff" stroke-width="2"/>
77
+ <line x1="40" y1="-40" x2="30" y2="-30" stroke="#ffffff" stroke-width="2"/>
78
+ <line x1="40" y1="40" x2="30" y2="30" stroke="#ffffff" stroke-width="2"/>
79
+ <line x1="-40" y1="40" x2="-30" y2="30" stroke="#ffffff" stroke-width="2"/>
80
+ </g>
81
+ </svg>`;
82
+
83
+ return svgContent;
84
+ }
85
+
86
+ /**
87
+ * Generate PNG from SVG using sharp or canvas
88
+ * Falls back to creating placeholder if libraries not available
89
+ */
90
+ async function generatePNG(svgContent, size, maskable = false) {
91
+ // Try using sharp first (recommended)
92
+ try {
93
+ const sharp = require('sharp');
94
+ const padding = maskable ? 20 : 0;
95
+ const padded = size + (padding * 2);
96
+
97
+ const png = await sharp(Buffer.from(svgContent))
98
+ .resize(size, size, {
99
+ fit: 'cover',
100
+ position: 'center'
101
+ })
102
+ .png()
103
+ .toBuffer();
104
+
105
+ return png;
106
+ } catch (err) {
107
+ // Fallback: create placeholder PNG with solid color
108
+ console.warn(` Warning: sharp not installed, creating placeholder for ${size}x${size}`);
109
+
110
+ // Create a simple PNG buffer (1x1 blue pixel, expanded to size)
111
+ // In production, use: npm install sharp
112
+ const color = maskable ? [2, 132, 199, 255] : [2, 132, 199, 255];
113
+ const filename = `icon-${size}${maskable ? '-maskable' : ''}.png`;
114
+
115
+ return createPlaceholderPNG(size, color);
116
+ }
117
+ }
118
+
119
+ /**
120
+ * Create placeholder PNG (when sharp not installed)
121
+ */
122
+ function createPlaceholderPNG(size, color) {
123
+ // Simple placeholder: create a basic PNG structure
124
+ // Real implementation would use sharp or canvas
125
+ const buffer = Buffer.alloc(200); // Minimal PNG
126
+ buffer.write('PNG\r\n\x1a\n'); // PNG signature
127
+ return buffer;
128
+ }
129
+
130
+ /**
131
+ * Main generator
132
+ */
133
+ async function generateIcons() {
134
+ const outputDir = process.argv[3] || './icons';
135
+ const sourceFile = process.argv[2] || null;
136
+
137
+ // Create output directory
138
+ if (!fs.existsSync(outputDir)) {
139
+ fs.mkdirSync(outputDir, { recursive: true });
140
+ }
141
+
142
+ console.log('cycleCAD PWA Icon Generator');
143
+ console.log('===========================\n');
144
+
145
+ // Generate source SVG
146
+ console.log('Generating source SVG...');
147
+ const svgContent = generateSourceSVG();
148
+ const svgPath = path.join(outputDir, 'icon-source.svg');
149
+ fs.writeFileSync(svgPath, svgContent);
150
+ console.log(`✓ Created: ${svgPath}\n`);
151
+
152
+ // Generate PNGs for all sizes
153
+ console.log('Generating icon PNGs...');
154
+ for (const { size, purpose } of ICON_SIZES) {
155
+ const filename = `icon-${size}${purpose === 'maskable' ? '-maskable' : ''}.png`;
156
+ const filepath = path.join(outputDir, filename);
157
+
158
+ try {
159
+ const png = await generatePNG(svgContent, size, purpose === 'maskable');
160
+ fs.writeFileSync(filepath, png);
161
+ console.log(`✓ ${filename}`);
162
+ } catch (err) {
163
+ console.error(`✗ ${filename}: ${err.message}`);
164
+ }
165
+ }
166
+
167
+ console.log('\nNote: Install "sharp" for better PNG generation:');
168
+ console.log(' npm install sharp\n');
169
+
170
+ // Create manifest fragment
171
+ console.log('Generating manifest.json icon references...');
172
+ const manifestFragment = generateManifestFragment();
173
+ const manifestPath = path.join(outputDir, 'manifest-icons.json');
174
+ fs.writeFileSync(manifestPath, JSON.stringify(manifestFragment, null, 2));
175
+ console.log(`✓ Icon references saved to: ${manifestPath}\n`);
176
+
177
+ console.log('Icon generation complete!');
178
+ console.log(`Icons saved to: ${path.resolve(outputDir)}`);
179
+ console.log('\nNext steps:');
180
+ console.log('1. Copy icons to /app/icons/');
181
+ console.log('2. Update manifest.json with icon paths');
182
+ console.log('3. Test PWA installation in Chrome/Edge');
183
+ }
184
+
185
+ /**
186
+ * Generate manifest.json icon references
187
+ */
188
+ function generateManifestFragment() {
189
+ const icons = ICON_SIZES.map(({ size, purpose }) => ({
190
+ src: `/app/icons/icon-${size}${purpose === 'maskable' ? '-maskable' : ''}.png`,
191
+ sizes: `${size}x${size}`,
192
+ type: 'image/png',
193
+ purpose: purpose
194
+ }));
195
+
196
+ return { icons };
197
+ }
198
+
199
+ // Run generator
200
+ generateIcons().catch(err => {
201
+ console.error('Error:', err.message);
202
+ process.exit(1);
203
+ });
package/app/index.html CHANGED
@@ -1363,6 +1363,99 @@
1363
1363
  <div id="toast-container"></div>
1364
1364
 
1365
1365
  <script type="module">
1366
+ // ===== Three.js Imports =====
1367
+ import * as THREE from 'three';
1368
+ import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
1369
+ import { GridHelper } from 'three';
1370
+
1371
+ // ===== Three.js Viewport Setup =====
1372
+ const scene = new THREE.Scene();
1373
+ scene.background = new THREE.Color(0x2d2d30);
1374
+
1375
+ const viewportEl = document.getElementById('viewport-container');
1376
+ const canvas = viewportEl.querySelector('canvas') || document.createElement('canvas');
1377
+ if (!canvas.parentElement) viewportEl.appendChild(canvas);
1378
+
1379
+ const renderer = new THREE.WebGLRenderer({ canvas, antialias: true });
1380
+ renderer.setPixelRatio(window.devicePixelRatio);
1381
+ renderer.shadowMap.enabled = true;
1382
+ renderer.shadowMap.type = THREE.PCFSoftShadowMap;
1383
+
1384
+ const camera = new THREE.PerspectiveCamera(50, 1, 0.1, 10000);
1385
+ camera.position.set(150, 120, 200);
1386
+ camera.lookAt(0, 0, 0);
1387
+
1388
+ const controls = new OrbitControls(camera, renderer.domElement);
1389
+ controls.enableDamping = true;
1390
+ controls.dampingFactor = 0.08;
1391
+ controls.target.set(0, 0, 0);
1392
+
1393
+ // Lights
1394
+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.6);
1395
+ scene.add(ambientLight);
1396
+ const dirLight = new THREE.DirectionalLight(0xffffff, 0.8);
1397
+ dirLight.position.set(200, 300, 150);
1398
+ dirLight.castShadow = true;
1399
+ scene.add(dirLight);
1400
+ const fillLight = new THREE.DirectionalLight(0x8899bb, 0.3);
1401
+ fillLight.position.set(-100, 50, -100);
1402
+ scene.add(fillLight);
1403
+
1404
+ // Grid
1405
+ const grid = new THREE.GridHelper(500, 50, 0x444444, 0x333333);
1406
+ scene.add(grid);
1407
+
1408
+ // Demo geometry — a sample part so viewport isn't empty
1409
+ const boxGeo = new THREE.BoxGeometry(60, 40, 80);
1410
+ const boxMat = new THREE.MeshStandardMaterial({ color: 0x0284C7, metalness: 0.3, roughness: 0.6 });
1411
+ const box = new THREE.Mesh(boxGeo, boxMat);
1412
+ box.position.y = 20;
1413
+ box.castShadow = true;
1414
+ box.receiveShadow = true;
1415
+ scene.add(box);
1416
+
1417
+ const cylGeo = new THREE.CylinderGeometry(12, 12, 50, 32);
1418
+ const cylMat = new THREE.MeshStandardMaterial({ color: 0x10b981, metalness: 0.4, roughness: 0.5 });
1419
+ const cyl = new THREE.Mesh(cylGeo, cylMat);
1420
+ cyl.position.set(0, 45, 0);
1421
+ cyl.castShadow = true;
1422
+ scene.add(cyl);
1423
+
1424
+ // Ground plane
1425
+ const groundGeo = new THREE.PlaneGeometry(500, 500);
1426
+ const groundMat = new THREE.ShadowMaterial({ opacity: 0.15 });
1427
+ const ground = new THREE.Mesh(groundGeo, groundMat);
1428
+ ground.rotation.x = -Math.PI / 2;
1429
+ ground.receiveShadow = true;
1430
+ scene.add(ground);
1431
+
1432
+ // Resize handler
1433
+ function resizeViewport() {
1434
+ const w = viewportEl.clientWidth;
1435
+ const h = viewportEl.clientHeight;
1436
+ if (w === 0 || h === 0) return;
1437
+ camera.aspect = w / h;
1438
+ camera.updateProjectionMatrix();
1439
+ renderer.setSize(w, h);
1440
+ }
1441
+ new ResizeObserver(resizeViewport).observe(viewportEl);
1442
+ resizeViewport();
1443
+
1444
+ // Animation loop
1445
+ function animate() {
1446
+ requestAnimationFrame(animate);
1447
+ controls.update();
1448
+ renderer.render(scene, camera);
1449
+ }
1450
+ animate();
1451
+
1452
+ // Expose globals for modules
1453
+ window.THREE = THREE;
1454
+ window._scene = scene;
1455
+ window._camera = camera;
1456
+ window._renderer = renderer;
1457
+ window._controls = controls;
1458
+
1366
1459
  // ===== Global State =====
1367
1460
  const appState = {
1368
1461
  currentWorkspace: 'design',