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.
- package/BILLING-IMPLEMENTATION-SUMMARY.md +425 -0
- package/BILLING-INDEX.md +293 -0
- package/BILLING-INTEGRATION-GUIDE.md +414 -0
- package/COLLABORATION-INDEX.md +440 -0
- package/COLLABORATION-SYSTEM-SUMMARY.md +548 -0
- package/DOCKER-BUILD-MANIFEST.txt +483 -0
- package/DOCKER-FILES-REFERENCE.md +440 -0
- package/DOCKER-INFRASTRUCTURE.md +475 -0
- package/DOCKER-README.md +435 -0
- package/Dockerfile +33 -55
- package/PWA-FILES-CREATED.txt +350 -0
- package/QUICK-START-TESTING.md +126 -0
- package/STEP-IMPORT-QUICKSTART.md +347 -0
- package/STEP-IMPORT-SYSTEM-SUMMARY.md +502 -0
- package/app/css/mobile.css +1074 -0
- package/app/icons/generate-icons.js +203 -0
- package/app/index.html +93 -0
- package/app/js/billing-ui.js +990 -0
- package/app/js/brep-kernel.js +933 -981
- package/app/js/collab-client.js +750 -0
- package/app/js/mobile-nav.js +623 -0
- package/app/js/mobile-toolbar.js +476 -0
- package/app/js/modules/billing-module.js +724 -0
- package/app/js/modules/step-module-enhanced.js +938 -0
- package/app/js/offline-manager.js +705 -0
- package/app/js/responsive-init.js +360 -0
- package/app/js/touch-handler.js +429 -0
- package/app/manifest.json +211 -0
- package/app/offline.html +508 -0
- package/app/sw.js +571 -0
- package/app/tests/billing-tests.html +779 -0
- package/app/tests/brep-tests.html +980 -0
- package/app/tests/collab-tests.html +743 -0
- package/app/tests/mobile-tests.html +1299 -0
- package/app/tests/pwa-tests.html +1134 -0
- package/app/tests/step-tests.html +1042 -0
- package/app/tests/test-agent-v3.html +719 -0
- package/docker-compose.yml +225 -0
- package/docs/BILLING-HELP.json +260 -0
- package/docs/BILLING-README.md +639 -0
- package/docs/BILLING-TUTORIAL.md +736 -0
- package/docs/BREP-HELP.json +326 -0
- package/docs/BREP-TUTORIAL.md +802 -0
- package/docs/COLLABORATION-HELP.json +228 -0
- package/docs/COLLABORATION-TUTORIAL.md +818 -0
- package/docs/DOCKER-HELP.json +224 -0
- package/docs/DOCKER-TUTORIAL.md +974 -0
- package/docs/MOBILE-HELP.json +243 -0
- package/docs/MOBILE-RESPONSIVE-README.md +378 -0
- package/docs/MOBILE-TUTORIAL.md +747 -0
- package/docs/PWA-HELP.json +228 -0
- package/docs/PWA-README.md +662 -0
- package/docs/PWA-TUTORIAL.md +757 -0
- package/docs/STEP-HELP.json +481 -0
- package/docs/STEP-IMPORT-TUTORIAL.md +824 -0
- package/docs/TESTING-GUIDE.md +528 -0
- package/docs/TESTING-HELP.json +182 -0
- package/fusion-vs-cyclecad.html +1771 -0
- package/nginx.conf +237 -0
- package/package.json +1 -1
- package/server/Dockerfile.converter +51 -0
- package/server/Dockerfile.signaling +28 -0
- package/server/billing-server.js +487 -0
- package/server/converter-enhanced.py +528 -0
- package/server/requirements-converter.txt +29 -0
- package/server/signaling-server.js +801 -0
- 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',
|