cyclecad 2.1.0 → 3.0.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/DELIVERABLES.txt +296 -445
- package/ENHANCEMENT_COMPLETION_REPORT.md +383 -0
- package/ENHANCEMENT_SUMMARY.txt +308 -0
- package/FEATURE_INVENTORY.md +235 -0
- package/FUSION360_FEATURES_SUMMARY.md +452 -0
- package/FUSION360_PARITY_ENHANCEMENTS.md +461 -0
- package/FUSION360_PARITY_SUMMARY.md +520 -0
- package/FUSION360_QUICK_REFERENCE.md +351 -0
- package/MODULE_API_REFERENCE.md +712 -0
- package/MODULE_INVENTORY.txt +264 -0
- package/app/index.html +1342 -5031
- package/app/js/app.js +1312 -514
- package/app/js/modules/animation-module.js +497 -3
- package/app/js/modules/cam-module.js +507 -2
- package/app/js/modules/collaboration-module.js +513 -0
- package/app/js/modules/constraint-module.js +1266 -0
- package/app/js/modules/data-module.js +544 -1146
- package/app/js/modules/formats-module.js +438 -738
- package/app/js/modules/inspection-module.js +393 -0
- package/app/js/modules/mesh-module-enhanced.js +880 -0
- package/app/js/modules/plugin-module.js +597 -0
- package/app/js/modules/rendering-module.js +460 -0
- package/app/js/modules/scripting-module.js +593 -475
- package/app/js/modules/sketch-module.js +998 -2
- package/app/js/modules/surface-module.js +312 -0
- package/app/js/modules/version-module.js +420 -0
- package/cycleCAD-Architecture-v2.pptx +0 -0
- package/package.json +1 -1
- package/~$cycleCAD-Architecture-v2.pptx +0 -0
|
@@ -1056,6 +1056,370 @@ export default {
|
|
|
1056
1056
|
};
|
|
1057
1057
|
},
|
|
1058
1058
|
|
|
1059
|
+
// ========================================================================
|
|
1060
|
+
// FUSION 360-PARITY ENHANCEMENTS: Branch Visualization
|
|
1061
|
+
// ========================================================================
|
|
1062
|
+
|
|
1063
|
+
/**
|
|
1064
|
+
* Get visual graph of branch/merge history.
|
|
1065
|
+
* Returns tree structure for rendering in UI.
|
|
1066
|
+
* @async
|
|
1067
|
+
* @returns {Promise<Object>} Graph: { nodes, edges }
|
|
1068
|
+
*/
|
|
1069
|
+
async getBranchGraph() {
|
|
1070
|
+
const nodes = [];
|
|
1071
|
+
const edges = [];
|
|
1072
|
+
|
|
1073
|
+
// Add branch nodes
|
|
1074
|
+
for (const [branchName, branch] of this.state.branches) {
|
|
1075
|
+
nodes.push({
|
|
1076
|
+
id: `branch-${branchName}`,
|
|
1077
|
+
label: branchName,
|
|
1078
|
+
type: 'branch',
|
|
1079
|
+
color: branchName === 'main' ? '#2196F3' : '#FF9800',
|
|
1080
|
+
});
|
|
1081
|
+
}
|
|
1082
|
+
|
|
1083
|
+
// Add version nodes (limited to main for clarity)
|
|
1084
|
+
const mainBranch = this.state.branches.get('main');
|
|
1085
|
+
if (mainBranch) {
|
|
1086
|
+
const mainVersions = this.state.versions.slice(0, 10); // Last 10 versions
|
|
1087
|
+
mainVersions.forEach((v, idx) => {
|
|
1088
|
+
nodes.push({
|
|
1089
|
+
id: `ver-${v.id}`,
|
|
1090
|
+
label: `v${v.number}`,
|
|
1091
|
+
type: 'version',
|
|
1092
|
+
timestamp: v.timestamp,
|
|
1093
|
+
message: v.message,
|
|
1094
|
+
branch: v.branch,
|
|
1095
|
+
});
|
|
1096
|
+
|
|
1097
|
+
// Connect versions to their parent
|
|
1098
|
+
if (v.parentVersionId) {
|
|
1099
|
+
edges.push({
|
|
1100
|
+
from: `ver-${v.id}`,
|
|
1101
|
+
to: `ver-${v.parentVersionId}`,
|
|
1102
|
+
type: 'parentChild',
|
|
1103
|
+
});
|
|
1104
|
+
}
|
|
1105
|
+
});
|
|
1106
|
+
}
|
|
1107
|
+
|
|
1108
|
+
return { nodes, edges };
|
|
1109
|
+
},
|
|
1110
|
+
|
|
1111
|
+
/**
|
|
1112
|
+
* Visualize 3D diff between two versions.
|
|
1113
|
+
* Shows added (green), removed (red), modified (orange) geometry.
|
|
1114
|
+
* @async
|
|
1115
|
+
* @param {Object} options
|
|
1116
|
+
* @param {string} options.versionId1 First version
|
|
1117
|
+
* @param {string} options.versionId2 Second version
|
|
1118
|
+
* @returns {Promise<Object>} Visual diff data
|
|
1119
|
+
*/
|
|
1120
|
+
async visualDiff(options = {}) {
|
|
1121
|
+
const { versionId1, versionId2 } = options;
|
|
1122
|
+
|
|
1123
|
+
const v1 = await this._getVersionFromDB(versionId1);
|
|
1124
|
+
const v2 = await this._getVersionFromDB(versionId2);
|
|
1125
|
+
|
|
1126
|
+
if (!v1 || !v2) {
|
|
1127
|
+
throw new Error('One or both versions not found');
|
|
1128
|
+
}
|
|
1129
|
+
|
|
1130
|
+
const diff = this._computeDiff(v1.modelState, v2.modelState);
|
|
1131
|
+
|
|
1132
|
+
// Broadcast event so UI can render split-view
|
|
1133
|
+
this._broadcastEvent('version:visualDiffRequested', {
|
|
1134
|
+
version1: v1,
|
|
1135
|
+
version2: v2,
|
|
1136
|
+
diff,
|
|
1137
|
+
});
|
|
1138
|
+
|
|
1139
|
+
return diff;
|
|
1140
|
+
},
|
|
1141
|
+
|
|
1142
|
+
// ========================================================================
|
|
1143
|
+
// FUSION 360-PARITY ENHANCEMENTS: Timeline & Thumbnails
|
|
1144
|
+
// ========================================================================
|
|
1145
|
+
|
|
1146
|
+
/**
|
|
1147
|
+
* Get scrollable timeline of versions for left panel.
|
|
1148
|
+
* Includes thumbnails, timestamps, messages.
|
|
1149
|
+
* @async
|
|
1150
|
+
* @returns {Promise<Array<Object>>}
|
|
1151
|
+
*/
|
|
1152
|
+
async getVersionTimeline() {
|
|
1153
|
+
return this.state.versions.map(v => ({
|
|
1154
|
+
id: v.id,
|
|
1155
|
+
number: v.number,
|
|
1156
|
+
timestamp: v.timestamp,
|
|
1157
|
+
message: v.message,
|
|
1158
|
+
tags: v.tags || [],
|
|
1159
|
+
thumbnail: v.thumbnail,
|
|
1160
|
+
author: v.author,
|
|
1161
|
+
branch: v.branch,
|
|
1162
|
+
}));
|
|
1163
|
+
},
|
|
1164
|
+
|
|
1165
|
+
/**
|
|
1166
|
+
* Preview a version without restoring (hover in timeline).
|
|
1167
|
+
* Temporarily shows 3D geometry in viewport.
|
|
1168
|
+
* @async
|
|
1169
|
+
* @param {string} versionId
|
|
1170
|
+
* @returns {Promise<void>}
|
|
1171
|
+
*/
|
|
1172
|
+
async previewVersion(versionId) {
|
|
1173
|
+
const version = await this._getVersionFromDB(versionId);
|
|
1174
|
+
if (!version) return;
|
|
1175
|
+
|
|
1176
|
+
this._broadcastEvent('version:previewing', version);
|
|
1177
|
+
},
|
|
1178
|
+
|
|
1179
|
+
/**
|
|
1180
|
+
* Clear preview (restore to current version).
|
|
1181
|
+
* @async
|
|
1182
|
+
* @returns {Promise<void>}
|
|
1183
|
+
*/
|
|
1184
|
+
async clearPreview() {
|
|
1185
|
+
this._broadcastEvent('version:previewCleared', {});
|
|
1186
|
+
},
|
|
1187
|
+
|
|
1188
|
+
// ========================================================================
|
|
1189
|
+
// FUSION 360-PARITY ENHANCEMENTS: Cherry-Pick & Feature Export
|
|
1190
|
+
// ========================================================================
|
|
1191
|
+
|
|
1192
|
+
/**
|
|
1193
|
+
* Cherry-pick individual features from a past version.
|
|
1194
|
+
* Restores only the selected features, not the entire version.
|
|
1195
|
+
* @async
|
|
1196
|
+
* @param {Object} options
|
|
1197
|
+
* @param {string} options.versionId Source version
|
|
1198
|
+
* @param {Array<string>} options.featureIds Features to restore
|
|
1199
|
+
* @returns {Promise<void>}
|
|
1200
|
+
*/
|
|
1201
|
+
async cherryPickFeatures(options = {}) {
|
|
1202
|
+
const { versionId, featureIds } = options;
|
|
1203
|
+
|
|
1204
|
+
const version = await this._getVersionFromDB(versionId);
|
|
1205
|
+
if (!version) {
|
|
1206
|
+
throw new Error(`Version ${versionId} not found`);
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
// Extract requested features from version's feature tree
|
|
1210
|
+
const selectedFeatures = version.modelState.featureTree.filter(f =>
|
|
1211
|
+
featureIds.includes(f.id)
|
|
1212
|
+
);
|
|
1213
|
+
|
|
1214
|
+
// Apply selected features to current model
|
|
1215
|
+
this._broadcastEvent('version:cherryPickingFeatures', {
|
|
1216
|
+
features: selectedFeatures,
|
|
1217
|
+
sourceVersion: versionId,
|
|
1218
|
+
});
|
|
1219
|
+
|
|
1220
|
+
this._showNotification(
|
|
1221
|
+
`Cherry-picked ${selectedFeatures.length} features from v${version.number}`,
|
|
1222
|
+
'success'
|
|
1223
|
+
);
|
|
1224
|
+
},
|
|
1225
|
+
|
|
1226
|
+
/**
|
|
1227
|
+
* Export a historical version as STEP/STL without switching.
|
|
1228
|
+
* @async
|
|
1229
|
+
* @param {Object} options
|
|
1230
|
+
* @param {string} options.versionId Version to export
|
|
1231
|
+
* @param {string} options.format 'step' | 'stl' | 'obj' | 'gltf'
|
|
1232
|
+
* @returns {Promise<Blob>}
|
|
1233
|
+
*/
|
|
1234
|
+
async exportVersionAs(options = {}) {
|
|
1235
|
+
const { versionId, format = 'step' } = options;
|
|
1236
|
+
|
|
1237
|
+
const version = await this._getVersionFromDB(versionId);
|
|
1238
|
+
if (!version) {
|
|
1239
|
+
throw new Error(`Version ${versionId} not found`);
|
|
1240
|
+
}
|
|
1241
|
+
|
|
1242
|
+
// This would integrate with export module
|
|
1243
|
+
this._broadcastEvent('version:exportingHistorical', {
|
|
1244
|
+
version,
|
|
1245
|
+
format,
|
|
1246
|
+
});
|
|
1247
|
+
|
|
1248
|
+
return new Blob(['[Export data would go here]']);
|
|
1249
|
+
},
|
|
1250
|
+
|
|
1251
|
+
// ========================================================================
|
|
1252
|
+
// FUSION 360-PARITY ENHANCEMENTS: Tags & Labels
|
|
1253
|
+
// ========================================================================
|
|
1254
|
+
|
|
1255
|
+
/**
|
|
1256
|
+
* Add tag/label to a version (e.g., 'Release', 'Review', 'Draft').
|
|
1257
|
+
* @async
|
|
1258
|
+
* @param {Object} options
|
|
1259
|
+
* @param {string} options.versionId
|
|
1260
|
+
* @param {string} options.tag Tag name
|
|
1261
|
+
* @returns {Promise<void>}
|
|
1262
|
+
*/
|
|
1263
|
+
async tagVersion(options = {}) {
|
|
1264
|
+
const { versionId, tag } = options;
|
|
1265
|
+
|
|
1266
|
+
const tx = this.state.db.transaction(['versions'], 'readwrite');
|
|
1267
|
+
const store = tx.objectStore('versions');
|
|
1268
|
+
const req = store.get(versionId);
|
|
1269
|
+
|
|
1270
|
+
req.onsuccess = () => {
|
|
1271
|
+
const version = req.result;
|
|
1272
|
+
if (version) {
|
|
1273
|
+
if (!version.tags) version.tags = [];
|
|
1274
|
+
if (!version.tags.includes(tag)) {
|
|
1275
|
+
version.tags.push(tag);
|
|
1276
|
+
}
|
|
1277
|
+
store.put(version);
|
|
1278
|
+
}
|
|
1279
|
+
};
|
|
1280
|
+
},
|
|
1281
|
+
|
|
1282
|
+
/**
|
|
1283
|
+
* Get all versions with a specific tag.
|
|
1284
|
+
* @async
|
|
1285
|
+
* @param {string} tag
|
|
1286
|
+
* @returns {Promise<Array<Object>>}
|
|
1287
|
+
*/
|
|
1288
|
+
async getVersionsByTag(tag) {
|
|
1289
|
+
return new Promise(resolve => {
|
|
1290
|
+
const tx = this.state.db.transaction(['versions'], 'readonly');
|
|
1291
|
+
const store = tx.objectStore('versions');
|
|
1292
|
+
const req = store.getAll();
|
|
1293
|
+
|
|
1294
|
+
req.onsuccess = () => {
|
|
1295
|
+
const tagged = req.result.filter(v =>
|
|
1296
|
+
v.tags && v.tags.includes(tag)
|
|
1297
|
+
);
|
|
1298
|
+
resolve(tagged);
|
|
1299
|
+
};
|
|
1300
|
+
});
|
|
1301
|
+
},
|
|
1302
|
+
|
|
1303
|
+
// ========================================================================
|
|
1304
|
+
// FUSION 360-PARITY ENHANCEMENTS: Undo/Redo Integration
|
|
1305
|
+
// ========================================================================
|
|
1306
|
+
|
|
1307
|
+
/**
|
|
1308
|
+
* Integration point: every undo operation creates a micro-version.
|
|
1309
|
+
* Allows rewinding undo history later.
|
|
1310
|
+
* @private
|
|
1311
|
+
*/
|
|
1312
|
+
_microVersionCount: 0,
|
|
1313
|
+
|
|
1314
|
+
/**
|
|
1315
|
+
* Track undo action (create micro-version).
|
|
1316
|
+
* @private
|
|
1317
|
+
* @async
|
|
1318
|
+
* @param {Object} operation { type, params }
|
|
1319
|
+
*/
|
|
1320
|
+
async _recordUndoOperation(operation) {
|
|
1321
|
+
this._microVersionCount++;
|
|
1322
|
+
|
|
1323
|
+
// Only save every 5th undo to avoid bloat
|
|
1324
|
+
if (this._microVersionCount % 5 === 0) {
|
|
1325
|
+
await this.save({
|
|
1326
|
+
message: `[Undo: ${operation.type}]`,
|
|
1327
|
+
tags: ['undo-micro'],
|
|
1328
|
+
});
|
|
1329
|
+
}
|
|
1330
|
+
},
|
|
1331
|
+
|
|
1332
|
+
/**
|
|
1333
|
+
* Restore from an undo micro-version.
|
|
1334
|
+
* @async
|
|
1335
|
+
* @param {string} microVersionId
|
|
1336
|
+
* @returns {Promise<void>}
|
|
1337
|
+
*/
|
|
1338
|
+
async restoreFromUndo(microVersionId) {
|
|
1339
|
+
return this.restore({ versionId: microVersionId });
|
|
1340
|
+
},
|
|
1341
|
+
|
|
1342
|
+
// ========================================================================
|
|
1343
|
+
// FUSION 360-PARITY ENHANCEMENTS: Storage & Cleanup
|
|
1344
|
+
// ========================================================================
|
|
1345
|
+
|
|
1346
|
+
/**
|
|
1347
|
+
* Get storage quota info (IndexedDB size).
|
|
1348
|
+
* @async
|
|
1349
|
+
* @returns {Promise<Object>} { used, quota, percentage }
|
|
1350
|
+
*/
|
|
1351
|
+
async getStorageInfo() {
|
|
1352
|
+
if (!navigator.storage?.estimate) {
|
|
1353
|
+
return { used: 0, quota: 0, percentage: 0 };
|
|
1354
|
+
}
|
|
1355
|
+
|
|
1356
|
+
const estimate = await navigator.storage.estimate();
|
|
1357
|
+
return {
|
|
1358
|
+
used: estimate.usage,
|
|
1359
|
+
quota: estimate.quota,
|
|
1360
|
+
percentage: Math.round((estimate.usage / estimate.quota) * 100),
|
|
1361
|
+
};
|
|
1362
|
+
},
|
|
1363
|
+
|
|
1364
|
+
/**
|
|
1365
|
+
* Auto-cleanup old versions when storage runs low.
|
|
1366
|
+
* Deletes oldest auto-saves, keeps manual saves.
|
|
1367
|
+
* @private
|
|
1368
|
+
* @async
|
|
1369
|
+
*/
|
|
1370
|
+
async _autoCleanupOldVersions() {
|
|
1371
|
+
const storageInfo = await this.getStorageInfo();
|
|
1372
|
+
|
|
1373
|
+
// If using >80% quota, clean up
|
|
1374
|
+
if (storageInfo.percentage > 80) {
|
|
1375
|
+
const tx = this.state.db.transaction(['versions'], 'readwrite');
|
|
1376
|
+
const store = tx.objectStore('versions');
|
|
1377
|
+
const req = store.getAll();
|
|
1378
|
+
|
|
1379
|
+
req.onsuccess = () => {
|
|
1380
|
+
const versions = req.result
|
|
1381
|
+
.filter(v => v.tags?.includes('auto-save'))
|
|
1382
|
+
.sort((a, b) => a.timestamp - b.timestamp)
|
|
1383
|
+
.slice(0, -10); // Keep last 10 auto-saves
|
|
1384
|
+
|
|
1385
|
+
versions.forEach(v => store.delete(v.id));
|
|
1386
|
+
console.log(`[Version] Cleaned up ${versions.length} old auto-saves`);
|
|
1387
|
+
};
|
|
1388
|
+
}
|
|
1389
|
+
},
|
|
1390
|
+
|
|
1391
|
+
/**
|
|
1392
|
+
* Manually trigger cleanup of old auto-saves.
|
|
1393
|
+
* @async
|
|
1394
|
+
* @param {Object} options
|
|
1395
|
+
* @param {number} [options.keepCount=10] How many auto-saves to keep
|
|
1396
|
+
* @returns {Promise<number>} Number of versions deleted
|
|
1397
|
+
*/
|
|
1398
|
+
async cleanupAutoSaves(options = {}) {
|
|
1399
|
+
const { keepCount = 10 } = options;
|
|
1400
|
+
|
|
1401
|
+
return new Promise(resolve => {
|
|
1402
|
+
const tx = this.state.db.transaction(['versions'], 'readwrite');
|
|
1403
|
+
const store = tx.objectStore('versions');
|
|
1404
|
+
const req = store.getAll();
|
|
1405
|
+
|
|
1406
|
+
req.onsuccess = () => {
|
|
1407
|
+
const autoSaves = req.result
|
|
1408
|
+
.filter(v => v.tags?.includes('auto-save'))
|
|
1409
|
+
.sort((a, b) => b.timestamp - a.timestamp);
|
|
1410
|
+
|
|
1411
|
+
const toDelete = autoSaves.slice(keepCount);
|
|
1412
|
+
toDelete.forEach(v => store.delete(v.id));
|
|
1413
|
+
|
|
1414
|
+
this._showNotification(
|
|
1415
|
+
`Cleaned up ${toDelete.length} old auto-saves`,
|
|
1416
|
+
'success'
|
|
1417
|
+
);
|
|
1418
|
+
resolve(toDelete.length);
|
|
1419
|
+
};
|
|
1420
|
+
});
|
|
1421
|
+
},
|
|
1422
|
+
|
|
1059
1423
|
// ========================================================================
|
|
1060
1424
|
// INTERNAL HELPERS — UI and Events
|
|
1061
1425
|
// ========================================================================
|
|
@@ -1149,6 +1513,62 @@ export default {
|
|
|
1149
1513
|
category: 'Version Control',
|
|
1150
1514
|
shortcut: null,
|
|
1151
1515
|
},
|
|
1516
|
+
{
|
|
1517
|
+
title: 'Branch Visualization',
|
|
1518
|
+
description:
|
|
1519
|
+
'View a graph of all branches and their merge history. Shows which versions are on which branches and how they diverged.',
|
|
1520
|
+
category: 'Version Control',
|
|
1521
|
+
shortcut: null,
|
|
1522
|
+
},
|
|
1523
|
+
{
|
|
1524
|
+
title: 'Visual Diff',
|
|
1525
|
+
description:
|
|
1526
|
+
'Select two versions to see a side-by-side 3D comparison. Added parts show green, removed show red, modified show orange.',
|
|
1527
|
+
category: 'Version Control',
|
|
1528
|
+
shortcut: null,
|
|
1529
|
+
},
|
|
1530
|
+
{
|
|
1531
|
+
title: 'Version Timeline',
|
|
1532
|
+
description:
|
|
1533
|
+
'Browse all versions in a scrollable timeline on the left panel. Hover to preview a version\'s 3D geometry without restoring.',
|
|
1534
|
+
category: 'Version Control',
|
|
1535
|
+
shortcut: null,
|
|
1536
|
+
},
|
|
1537
|
+
{
|
|
1538
|
+
title: 'Cherry-Pick Features',
|
|
1539
|
+
description:
|
|
1540
|
+
'Restore only specific features from a past version, not the entire model. Select features in the version panel to cherry-pick.',
|
|
1541
|
+
category: 'Version Control',
|
|
1542
|
+
shortcut: null,
|
|
1543
|
+
},
|
|
1544
|
+
{
|
|
1545
|
+
title: 'Export Historical Version',
|
|
1546
|
+
description:
|
|
1547
|
+
'Export any past version as STEP, STL, OBJ, or glTF without switching to it. Right-click a version and choose Export As.',
|
|
1548
|
+
category: 'Version Control',
|
|
1549
|
+
shortcut: null,
|
|
1550
|
+
},
|
|
1551
|
+
{
|
|
1552
|
+
title: 'Version Tags',
|
|
1553
|
+
description:
|
|
1554
|
+
'Mark versions with tags like "Release", "Review", or "Draft" for easy organization. Filter timeline by tag to find important milestones.',
|
|
1555
|
+
category: 'Version Control',
|
|
1556
|
+
shortcut: null,
|
|
1557
|
+
},
|
|
1558
|
+
{
|
|
1559
|
+
title: 'Undo Micro-Versions',
|
|
1560
|
+
description:
|
|
1561
|
+
'Every 5 undo operations automatically creates a micro-version. You can restore from these if you accidentally undo too far.',
|
|
1562
|
+
category: 'Version Control',
|
|
1563
|
+
shortcut: null,
|
|
1564
|
+
},
|
|
1565
|
+
{
|
|
1566
|
+
title: 'Storage Management',
|
|
1567
|
+
description:
|
|
1568
|
+
'View IndexedDB storage quota in Version panel. Auto-cleanup removes old auto-saves when storage is >80% full. Manual cleanup available.',
|
|
1569
|
+
category: 'Version Control',
|
|
1570
|
+
shortcut: null,
|
|
1571
|
+
},
|
|
1152
1572
|
],
|
|
1153
1573
|
|
|
1154
1574
|
// ========================================================================
|
|
Binary file
|
package/package.json
CHANGED
|
Binary file
|