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,818 @@
1
+ # cycleCAD Live Collaboration Tutorial
2
+
3
+ ## What is Real-Time Collaboration in CAD?
4
+
5
+ Real-time collaboration enables multiple engineers to work on the same 3D model simultaneously, seeing each other's cursors, selections, and edits in live time. Instead of emailing files back and forth or merging conflicts manually, everyone is always working on the latest version.
6
+
7
+ ### Key Benefits
8
+ - **Live cursor sharing** — See where each team member is looking
9
+ - **Live selection sync** — Know which parts others are editing
10
+ - **Operation replay** — All changes are logged and can be reviewed
11
+ - **Chat & comments** — Discuss designs without leaving the app
12
+ - **Offline support** — Changes queue and sync when reconnected
13
+
14
+ ---
15
+
16
+ ## Architecture Overview
17
+
18
+ ```
19
+ ┌─────────────────────────────────────────────────────────┐
20
+ │ cycleCAD Collaboration System │
21
+ ├─────────────────────────────────────────────────────────┤
22
+ │ │
23
+ │ ┌──────────┐ ┌──────────┐ ┌──────────┐ │
24
+ │ │ User A │ │ User B │ │ User C │ │
25
+ │ │ Browser │ │ Browser │ │ Browser │ │
26
+ │ └────┬─────┘ └────┬─────┘ └────┬─────┘ │
27
+ │ │ │ │ │
28
+ │ └──────────────────┼──────────────────┘ │
29
+ │ │ │
30
+ │ ┌─────▼──────┐ │
31
+ │ │ WebSocket │ │
32
+ │ │ Bridge │ │
33
+ │ └─────┬──────┘ │
34
+ │ │ │
35
+ │ ┌──────────────────┼──────────────────┐ │
36
+ │ │ │ │ │
37
+ │ ┌────▼─────┐ ┌──────▼──────┐ ┌─────▼────┐ │
38
+ │ │ Signaling │ │ CRDT │ │ Chat │ │
39
+ │ │ Server │ │ Engine │ │ Server │ │
40
+ │ └───────────┘ └─────────────┘ └──────────┘ │
41
+ │ │ │
42
+ │ ┌──────▼──────┐ │
43
+ │ │ Room State │ │
44
+ │ │ (Persisted) │ │
45
+ │ └─────────────┘ │
46
+ └─────────────────────────────────────────────────────────┘
47
+ ```
48
+
49
+ ### Components
50
+
51
+ 1. **Signaling Server** (`server/signaling-server.js`)
52
+ - Manages WebSocket connections
53
+ - Routes messages between clients
54
+ - Maintains room state and user presence
55
+ - Persists operations to disk
56
+
57
+ 2. **Collaboration Client** (`app/js/collab-client.js`)
58
+ - Browser-side WebSocket manager
59
+ - Handles WebRTC peer connections
60
+ - Implements offline queue
61
+ - Auto-reconnect with exponential backoff
62
+
63
+ 3. **CRDT Engine** (integrated in app.js)
64
+ - Last-writer-wins (LWW) for simple properties
65
+ - Operation log for geometry changes
66
+ - Conflict resolution without central server
67
+
68
+ ---
69
+
70
+ ## Setting Up the Signaling Server
71
+
72
+ ### Local Development
73
+
74
+ #### Option 1: Direct Node.js
75
+
76
+ ```bash
77
+ # Install dependencies
78
+ npm install ws express
79
+
80
+ # Start the signaling server
81
+ node server/signaling-server.js
82
+ ```
83
+
84
+ Server runs on `ws://localhost:8788` with HTTP health checks at `http://localhost:8788/health`.
85
+
86
+ #### Option 2: npm script
87
+
88
+ Add to `package.json`:
89
+
90
+ ```json
91
+ {
92
+ "scripts": {
93
+ "collab:server": "node server/signaling-server.js",
94
+ "collab:server:dev": "NODE_ENV=development node server/signaling-server.js"
95
+ }
96
+ }
97
+ ```
98
+
99
+ Run:
100
+
101
+ ```bash
102
+ npm run collab:server
103
+ ```
104
+
105
+ ### Docker Deployment
106
+
107
+ #### Build the image
108
+
109
+ ```bash
110
+ docker build -t cyclecad-signaling -f server/Dockerfile.signaling server/
111
+ ```
112
+
113
+ #### Run the container
114
+
115
+ ```bash
116
+ docker run -p 8788:8788 cyclecad-signaling
117
+ ```
118
+
119
+ #### With docker-compose
120
+
121
+ ```bash
122
+ docker-compose up signaling
123
+ ```
124
+
125
+ ### Cloud Deployment
126
+
127
+ #### AWS (Lightsail)
128
+
129
+ 1. Create a Node.js instance
130
+ 2. Upload `server/signaling-server.js` and `package.json`
131
+ 3. Install dependencies: `npm install`
132
+ 4. Use PM2 for process management: `npm install -g pm2 && pm2 start server/signaling-server.js`
133
+ 5. Configure security group to allow port 8788
134
+ 6. Use Route 53 to point `collab.cyclecad.com` to the instance
135
+
136
+ #### Google Cloud (Cloud Run)
137
+
138
+ Create `Dockerfile`:
139
+
140
+ ```dockerfile
141
+ FROM node:20-alpine
142
+ WORKDIR /app
143
+ COPY server/package.json .
144
+ RUN npm install
145
+ COPY server/ .
146
+ EXPOSE 8788
147
+ CMD ["node", "signaling-server.js"]
148
+ ```
149
+
150
+ Deploy:
151
+
152
+ ```bash
153
+ gcloud run deploy cyclecad-signaling \
154
+ --source . \
155
+ --platform managed \
156
+ --allow-unauthenticated
157
+ ```
158
+
159
+ #### Heroku
160
+
161
+ ```bash
162
+ git push heroku main
163
+ ```
164
+
165
+ ---
166
+
167
+ ## Client-Side Integration
168
+
169
+ ### 1. Initialize the Collaboration Client
170
+
171
+ In your `app/js/app.js`:
172
+
173
+ ```javascript
174
+ // Initialize collaboration client
175
+ const collabClient = new CollaborationClient('ws://localhost:8788');
176
+
177
+ // Or connect to cloud server:
178
+ // const collabClient = new CollaborationClient('wss://collab.cyclecad.com');
179
+
180
+ // Set up event callbacks
181
+ collabClient.on('connected', () => {
182
+ console.log('Connected to collaboration server');
183
+ updateUI('collaborationStatus', 'Connected');
184
+ });
185
+
186
+ collabClient.on('disconnected', () => {
187
+ console.log('Disconnected from collaboration server');
188
+ updateUI('collaborationStatus', 'Disconnected');
189
+ });
190
+
191
+ collabClient.on('userJoined', ({ userId, name, color }) => {
192
+ console.log(`${name} joined the session`);
193
+ renderUserInList(userId, name, color);
194
+ });
195
+
196
+ collabClient.on('userLeft', ({ userId }) => {
197
+ console.log(`User ${userId} left`);
198
+ removeUserFromList(userId);
199
+ });
200
+
201
+ collabClient.on('operationReceived', ({ userId, op, timestamp }) => {
202
+ applyRemoteOperation(op);
203
+ });
204
+
205
+ collabClient.on('chatMessage', ({ name, color, text, timestamp }) => {
206
+ appendChatMessage(name, text, color, timestamp);
207
+ });
208
+
209
+ collabClient.on('cursorUpdate', ({ userId, x, y }) => {
210
+ renderRemoteCursor(userId, x, y);
211
+ });
212
+
213
+ collabClient.on('error', (error) => {
214
+ console.error('Collaboration error:', error);
215
+ showErrorNotification(error.message);
216
+ });
217
+ ```
218
+
219
+ ### 2. Create or Join a Room
220
+
221
+ ```javascript
222
+ // Create a new collaboration room
223
+ function createCollaborationSession() {
224
+ const roomId = `project-${Date.now()}`;
225
+ const sessionName = prompt('Session name:') || `Session ${roomId}`;
226
+
227
+ collabClient.createRoom(roomId, {
228
+ name: sessionName,
229
+ maxUsers: 10
230
+ });
231
+
232
+ setTimeout(() => {
233
+ collabClient.joinRoom(
234
+ roomId,
235
+ 'user-' + crypto.getRandomValues(new Uint8Array(4)).join('-'),
236
+ prompt('Your name:') || 'Anonymous Engineer'
237
+ );
238
+ }, 500);
239
+ }
240
+
241
+ // Join an existing room
242
+ function joinCollaborationSession() {
243
+ const roomId = prompt('Enter room ID:');
244
+ const userName = prompt('Your name:') || 'Anonymous Engineer';
245
+ const password = prompt('Room password (if private):') || null;
246
+
247
+ collabClient.joinRoom(
248
+ roomId,
249
+ 'user-' + crypto.getRandomValues(new Uint8Array(4)).join('-'),
250
+ userName,
251
+ password
252
+ );
253
+ }
254
+ ```
255
+
256
+ ### 3. Share Cursor Position
257
+
258
+ Track mouse movement and send to server (throttled):
259
+
260
+ ```javascript
261
+ // Listen to mouse moves in the 3D viewport
262
+ document.addEventListener('mousemove', (event) => {
263
+ // Normalize to viewport coordinates
264
+ const rect = viewport.domElement.getBoundingClientRect();
265
+ const x = (event.clientX - rect.left) / rect.width;
266
+ const y = (event.clientY - rect.top) / rect.height;
267
+
268
+ collabClient.updateCursor(x, y);
269
+ });
270
+ ```
271
+
272
+ ### 4. Share Part Selection
273
+
274
+ When user selects a part:
275
+
276
+ ```javascript
277
+ function onPartSelected(partId) {
278
+ // Local selection
279
+ selectedParts = [partId];
280
+
281
+ // Broadcast to collaborators
282
+ collabClient.updateSelection(selectedParts);
283
+ }
284
+
285
+ function onMultiSelect(partIds) {
286
+ selectedParts = partIds;
287
+ collabClient.updateSelection(partIds);
288
+ }
289
+ ```
290
+
291
+ ### 5. Send Operations
292
+
293
+ When user performs a geometry operation:
294
+
295
+ ```javascript
296
+ function onExtrude(sketchId, depth) {
297
+ const op = {
298
+ type: 'extrude',
299
+ sketchId,
300
+ depth,
301
+ timestamp: Date.now()
302
+ };
303
+
304
+ // Apply locally
305
+ applyExtrude(sketchId, depth);
306
+
307
+ // Send to collaborators
308
+ collabClient.sendOperation(op);
309
+ }
310
+ ```
311
+
312
+ ### 6. Chat Integration
313
+
314
+ Send and receive chat messages:
315
+
316
+ ```javascript
317
+ function sendChatMessage(text) {
318
+ if (!text.trim()) return;
319
+
320
+ collabClient.sendMessage(text);
321
+
322
+ // Clear input
323
+ document.querySelector('#chat-input').value = '';
324
+ }
325
+
326
+ // In collabClient.on('chatMessage', ...) callback
327
+ function appendChatMessage(name, text, color, timestamp) {
328
+ const chatPanel = document.querySelector('#chat-panel');
329
+ const msg = document.createElement('div');
330
+ msg.className = 'chat-message';
331
+ msg.style.borderLeft = `3px solid ${color}`;
332
+ msg.innerHTML = `
333
+ <span class="chat-name" style="color: ${color};">${escapeHtml(name)}</span>
334
+ <span class="chat-text">${escapeHtml(text)}</span>
335
+ <span class="chat-time">${new Date(timestamp).toLocaleTimeString()}</span>
336
+ `;
337
+ chatPanel.appendChild(msg);
338
+ chatPanel.scrollTop = chatPanel.scrollHeight;
339
+ }
340
+ ```
341
+
342
+ ---
343
+
344
+ ## How WebRTC P2P Works
345
+
346
+ Once signaling is complete, direct peer-to-peer connections are established:
347
+
348
+ ### 1. Signaling Phase (via WebSocket)
349
+
350
+ ```
351
+ User A (Browser) Signaling Server User B (Browser)
352
+ │ │ │
353
+ │──────── Offer ─────────────────>│ │
354
+ │ │────── Offer ──────────────>│
355
+ │ │ │
356
+ │<────── ICE Candidates ──────────│<────────────────────────────│
357
+ │ │ │
358
+ │<────── Answer ─────────────────│ │
359
+ │ │<────── Answer ─────────────│
360
+ │ │ │
361
+ ```
362
+
363
+ ### 2. Direct P2P Phase (DataChannel)
364
+
365
+ ```
366
+ User A (Browser) <──────────────────── DataChannel ────────────────> User B (Browser)
367
+ (Low latency, high bandwidth)
368
+ ```
369
+
370
+ ### Key WebRTC Details
371
+
372
+ - **STUN servers**: Public servers that help discover your public IP for NAT traversal
373
+ - **TURN servers**: Relay servers if direct P2P isn't possible (firewall/NAT restrictions)
374
+ - **Data channels**: Ordered, reliable messaging between peers (like a WebSocket but P2P)
375
+
376
+ ---
377
+
378
+ ## CRDT Basics and Conflict Resolution
379
+
380
+ Conflict-free Replicated Data Type (CRDT) allows all users to apply operations independently without central coordination.
381
+
382
+ ### Approach 1: Last-Writer-Wins (LWW)
383
+
384
+ Simple properties like part name or visibility:
385
+
386
+ ```javascript
387
+ // User A: renames part to "Housing"
388
+ collabClient.sendOperation({
389
+ type: 'rename',
390
+ partId: 'part-123',
391
+ name: 'Housing',
392
+ timestamp: 1711000000000
393
+ });
394
+
395
+ // User B: renames same part to "Enclosure"
396
+ collabClient.sendOperation({
397
+ type: 'rename',
398
+ partId: 'part-123',
399
+ name: 'Enclosure',
400
+ timestamp: 1711000001000 // User B's change came 1 second later
401
+ });
402
+
403
+ // Result: Part is renamed to "Enclosure" (timestamp wins)
404
+ ```
405
+
406
+ ### Approach 2: Operation Log
407
+
408
+ Geometry operations are cumulative — order matters:
409
+
410
+ ```javascript
411
+ // User A performs operation at index 42
412
+ collabClient.sendOperation({
413
+ type: 'fillet',
414
+ edgeId: 'edge-456',
415
+ radius: 5,
416
+ operationIndex: 42
417
+ });
418
+
419
+ // User B sees User A's op and applies it locally
420
+ // Then User B performs operation at index 43
421
+ collabClient.sendOperation({
422
+ type: 'chamfer',
423
+ edgeId: 'edge-789',
424
+ distance: 2,
425
+ operationIndex: 43
426
+ });
427
+
428
+ // Both users end up with [op0, op1, ..., op42, op43] in same order
429
+ ```
430
+
431
+ ### Approach 3: Vector Clocks
432
+
433
+ For partial ordering (if needed):
434
+
435
+ ```javascript
436
+ // Each client maintains a vector clock
437
+ const vectorClock = {
438
+ 'user-a': 5,
439
+ 'user-b': 3,
440
+ 'user-c': 2
441
+ };
442
+
443
+ // User A's next operation is: [6, 3, 2]
444
+ // User C's next operation is: [5, 3, 3]
445
+
446
+ // If clocks differ, we can determine causality
447
+ // and apply operations in the right order
448
+ ```
449
+
450
+ ---
451
+
452
+ ## Offline Mode and Reconnection
453
+
454
+ When the client loses connection:
455
+
456
+ ```
457
+ ┌─────────────────────────────────────────┐
458
+ │ Offline Operation Queue │
459
+ ├─────────────────────────────────────────┤
460
+ │ Op 1: Extrude sketch-1, depth=10 │
461
+ │ Op 2: Fillet edge-5, radius=2 │
462
+ │ Op 3: Rename part-3 → "Housing" │
463
+ │ Op 4: Hide part-1 │
464
+ └─────────────────────────────────────────┘
465
+ ```
466
+
467
+ When reconnected:
468
+
469
+ ```javascript
470
+ // CollaborationClient automatically:
471
+ // 1. Detects connection restored
472
+ // 2. Replays all queued operations
473
+ // 3. Syncs server state
474
+
475
+ collabClient.on('connected', () => {
476
+ // Queue will be synced automatically
477
+ console.log('Offline operations synced');
478
+ });
479
+ ```
480
+
481
+ ---
482
+
483
+ ## Security Considerations
484
+
485
+ ### 1. Room Passwords
486
+
487
+ Protect rooms with optional passwords:
488
+
489
+ ```javascript
490
+ collabClient.createRoom('secret-project', {
491
+ password: 'my-secure-password-123',
492
+ maxUsers: 5
493
+ });
494
+
495
+ // Others must provide password to join
496
+ collabClient.joinRoom(
497
+ 'secret-project',
498
+ userId,
499
+ userName,
500
+ 'my-secure-password-123' // Must match
501
+ );
502
+ ```
503
+
504
+ ### 2. JWT Authentication (Optional)
505
+
506
+ For production, add JWT tokens to handshake:
507
+
508
+ ```javascript
509
+ const token = await fetch('/api/auth/token').then(r => r.json());
510
+
511
+ collabClient.ws.send(JSON.stringify({
512
+ type: 'authenticate',
513
+ token: token.jwt,
514
+ userId: token.userId
515
+ }));
516
+ ```
517
+
518
+ ### 3. TLS/SSL
519
+
520
+ Always use `wss://` (secure WebSocket) in production:
521
+
522
+ ```javascript
523
+ const isProduction = window.location.protocol === 'https:';
524
+ const signalServerUrl = isProduction
525
+ ? 'wss://collab.cyclecad.com'
526
+ : 'ws://localhost:8788';
527
+ ```
528
+
529
+ ---
530
+
531
+ ## Troubleshooting
532
+
533
+ ### WebSocket Connection Fails
534
+
535
+ **Symptom**: "Cannot connect to signaling server"
536
+
537
+ **Causes**:
538
+ - Signaling server not running
539
+ - Wrong URL (check http://localhost:8788/health)
540
+ - Firewall blocking port 8788
541
+ - CORS issues
542
+
543
+ **Fix**:
544
+ ```bash
545
+ # Check server health
546
+ curl http://localhost:8788/health
547
+
548
+ # Verify port is open
549
+ lsof -i :8788
550
+
551
+ # Check firewall rules
552
+ sudo ufw status
553
+ ```
554
+
555
+ ### Cursor Updates Lag
556
+
557
+ **Symptom**: Remote cursors update slowly or jerkily
558
+
559
+ **Causes**:
560
+ - Network latency
561
+ - Throttle interval too long (default 100ms)
562
+ - Browser performance issues
563
+
564
+ **Fix**:
565
+ ```javascript
566
+ // Reduce throttle interval
567
+ collabClient.cursorUpdateInterval = 50; // 50ms instead of 100ms
568
+
569
+ // Or increase if bandwidth is constrained
570
+ collabClient.cursorUpdateInterval = 200; // 200ms
571
+ ```
572
+
573
+ ### WebRTC Data Channel Never Opens
574
+
575
+ **Symptom**: P2P messages not being sent
576
+
577
+ **Causes**:
578
+ - STUN/TURN server unreachable
579
+ - Strict firewall/NAT
580
+ - Browser doesn't support WebRTC DataChannels
581
+
582
+ **Fix**:
583
+ ```javascript
584
+ // Add TURN servers for fallback
585
+ collabClient.iceServers = [
586
+ { urls: 'stun:stun.l.google.com:19302' },
587
+ {
588
+ urls: 'turn:turnserver.example.com',
589
+ username: 'user',
590
+ credential: 'pass'
591
+ }
592
+ ];
593
+ ```
594
+
595
+ ### Operations Not Syncing
596
+
597
+ **Symptom**: User A's edits not visible to User B
598
+
599
+ **Causes**:
600
+ - Operation not sent before closing connection
601
+ - Server not relaying operations
602
+ - Client ignoring remote operations
603
+
604
+ **Fix**:
605
+ ```javascript
606
+ // Ensure operation is sent
607
+ collabClient.on('operation', (message) => {
608
+ console.log('Received operation:', message);
609
+ // Debug: Are we getting the message?
610
+ });
611
+
612
+ // Check server logs
613
+ tail -f ~/.cyclecad/rooms-state.json
614
+ ```
615
+
616
+ ### Room Persistence Not Working
617
+
618
+ **Symptom**: Room state lost after server restart
619
+
620
+ **Cause**: State file not being saved
621
+
622
+ **Fix**:
623
+ ```bash
624
+ # Check state file exists
625
+ ls -la /path/to/rooms-state.json
626
+
627
+ # Check permissions
628
+ chmod 644 rooms-state.json
629
+
630
+ # Verify server can write
631
+ sudo -u nobody touch /path/to/test-write.txt
632
+ ```
633
+
634
+ ---
635
+
636
+ ## API Reference
637
+
638
+ ### CollaborationClient
639
+
640
+ ```javascript
641
+ // Constructor
642
+ const client = new CollaborationClient(signalServerUrl);
643
+
644
+ // Events
645
+ client.on('connected', callback);
646
+ client.on('disconnected', callback);
647
+ client.on('userJoined', callback);
648
+ client.on('userLeft', callback);
649
+ client.on('operationReceived', callback);
650
+ client.on('chatMessage', callback);
651
+ client.on('cursorUpdate', callback);
652
+ client.on('selectionUpdate', callback);
653
+ client.on('error', callback);
654
+
655
+ // Room management
656
+ client.createRoom(roomId, options);
657
+ client.joinRoom(roomId, userId, userName, password);
658
+ client.leaveRoom();
659
+
660
+ // Sharing
661
+ client.updateCursor(x, y);
662
+ client.updateSelection(partIds);
663
+ client.sendOperation(op);
664
+ client.sendMessage(text);
665
+
666
+ // Info
667
+ client.getUsers();
668
+ client.getUser(userId);
669
+ client.getRoomInfo();
670
+
671
+ // Connection
672
+ client.connect();
673
+ client.disconnect();
674
+ ```
675
+
676
+ ### Signaling Server REST API
677
+
678
+ ```bash
679
+ # Health check
680
+ GET /health
681
+ → { status: 'healthy', clients: 5, rooms: 2 }
682
+
683
+ # Server stats
684
+ GET /stats
685
+ → { clients: 5, rooms: 2, uptime: 3600, memory: {...} }
686
+
687
+ # List all rooms
688
+ GET /rooms
689
+ → { count: 2, rooms: [{id, name, users, ...}, ...] }
690
+
691
+ # Get specific room
692
+ GET /rooms/:roomId
693
+ → { room: {...} }
694
+
695
+ # Reset room (clear operations)
696
+ POST /rooms/:roomId/reset
697
+
698
+ # Close room
699
+ POST /rooms/:roomId/close
700
+ ```
701
+
702
+ ---
703
+
704
+ ## Example: Full Collaboration Session
705
+
706
+ ```javascript
707
+ // 1. Initialize client
708
+ const collab = new CollaborationClient('wss://collab.cyclecad.com');
709
+
710
+ // 2. Handle events
711
+ collab.on('connected', () => {
712
+ document.getElementById('status').textContent = '🟢 Connected';
713
+ });
714
+
715
+ collab.on('userJoined', ({ name }) => {
716
+ showNotification(`${name} joined the session`);
717
+ });
718
+
719
+ collab.on('operationReceived', ({ op }) => {
720
+ // Apply operation from remote user
721
+ const result = applyOperation(op);
722
+ updateViewport(result);
723
+ });
724
+
725
+ // 3. Create session
726
+ function newSession() {
727
+ const roomId = `session-${Date.now()}`;
728
+ collab.createRoom(roomId, { maxUsers: 10 });
729
+
730
+ setTimeout(() => {
731
+ collab.joinRoom(
732
+ roomId,
733
+ 'user-' + generateId(),
734
+ 'John Doe'
735
+ );
736
+
737
+ // Show share link
738
+ showShareLink(`cyclecad.com?room=${roomId}`);
739
+ }, 500);
740
+ }
741
+
742
+ // 4. Perform operation
743
+ function performExtrude(depth) {
744
+ const op = { type: 'extrude', depth, timestamp: Date.now() };
745
+
746
+ // Local
747
+ applyOperation(op);
748
+
749
+ // Remote
750
+ collab.sendOperation(op);
751
+ }
752
+
753
+ // 5. Chat
754
+ document.querySelector('#send-btn').onclick = () => {
755
+ const text = document.querySelector('#chat-input').value;
756
+ collab.sendMessage(text);
757
+ };
758
+ ```
759
+
760
+ ---
761
+
762
+ ## Performance Tuning
763
+
764
+ ### Reduce Message Rate
765
+
766
+ ```javascript
767
+ // Default cursor throttle is 100ms = 10 updates/sec
768
+ // For faster networks:
769
+ collabClient.cursorUpdateInterval = 50; // 20 updates/sec
770
+
771
+ // For slower networks:
772
+ collabClient.cursorUpdateInterval = 200; // 5 updates/sec
773
+ ```
774
+
775
+ ### Operation Batching
776
+
777
+ ```javascript
778
+ // Batch multiple operations before sending
779
+ const batch = [];
780
+
781
+ batch.push({ type: 'extrude', depth: 10 });
782
+ batch.push({ type: 'fillet', radius: 2 });
783
+
784
+ collabClient.send({
785
+ type: 'batch-operation',
786
+ operations: batch
787
+ });
788
+ ```
789
+
790
+ ### Memory Management
791
+
792
+ ```javascript
793
+ // Limit operation history
794
+ if (collabClient.operations.length > 10000) {
795
+ collabClient.operations = collabClient.operations.slice(-5000);
796
+ }
797
+
798
+ // Limit chat history
799
+ if (collabClient.chatMessages.length > 500) {
800
+ collabClient.chatMessages = collabClient.chatMessages.slice(-250);
801
+ }
802
+ ```
803
+
804
+ ---
805
+
806
+ ## Next Steps
807
+
808
+ 1. **Deploy server**: Choose hosting (Docker, AWS, GCP, Heroku)
809
+ 2. **Integrate client**: Wire `collab-client.js` into your app
810
+ 3. **Test locally**: Run signaling server and open 2 browser windows
811
+ 4. **Add UI**: Create collaboration panel with user list, chat, cursor display
812
+ 5. **Monitor**: Set up logging and alerting for server health
813
+
814
+ For more details, see:
815
+ - `server/signaling-server.js` — Full server source
816
+ - `app/js/collab-client.js` — Full client source
817
+ - `docs/COLLABORATION-HELP.json` — User-facing help
818
+