cyclecad 1.0.4 → 1.0.5

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/app/index.html CHANGED
@@ -1419,7 +1419,7 @@
1419
1419
  <span class="splash-logo-cycle">cycle</span><span class="splash-logo-cad">CAD</span>
1420
1420
  </div>
1421
1421
  <p class="splash-subtitle">Parametric 3D CAD Modeler for the Mechanical Designer</p>
1422
- <p style="display:inline-block; color:#0066cc; font-size:1rem; margin:12px 0 0 0; letter-spacing:2px; font-family:monospace; font-weight:700; background:rgba(0,102,204,0.08); border:1.5px solid rgba(0,102,204,0.25); border-radius:8px; padding:5px 20px;">v1.0.4</p>
1422
+ <p style="display:inline-block; color:#0066cc; font-size:1rem; margin:12px 0 0 0; letter-spacing:2px; font-family:monospace; font-weight:700; background:rgba(0,102,204,0.08); border:1.5px solid rgba(0,102,204,0.25); border-radius:8px; padding:5px 20px;">v1.0.5</p>
1423
1423
  </div>
1424
1424
  <div class="splash-options">
1425
1425
  <button class="splash-button splash-button-primary" id="btn-empty-project" style="grid-column: 1 / -1;">
@@ -4029,7 +4029,31 @@
4029
4029
  panel.style.cssText = 'position:fixed;top:60px;right:320px;width:420px;max-height:80vh;overflow-y:auto;background:var(--bg-secondary);border:1px solid var(--border-color);border-radius:8px;z-index:500;display:flex;flex-direction:column;box-shadow:var(--shadow-lg);';
4030
4030
 
4031
4031
  const header = document.createElement('div');
4032
- header.style.cssText = 'display:flex;justify-content:space-between;align-items:center;padding:10px 14px;border-bottom:1px solid var(--border-color);background:var(--bg-tertiary);border-radius:8px 8px 0 0;cursor:move;';
4032
+ header.style.cssText = 'display:flex;justify-content:space-between;align-items:center;padding:10px 14px;border-bottom:1px solid var(--border-color);background:var(--bg-tertiary);border-radius:8px 8px 0 0;cursor:move;user-select:none;';
4033
+
4034
+ // Make panel draggable by header
4035
+ let isDragging = false;
4036
+ let dragOffsetX = 0;
4037
+ let dragOffsetY = 0;
4038
+
4039
+ header.addEventListener('mousedown', (e) => {
4040
+ isDragging = true;
4041
+ const rect = panel.getBoundingClientRect();
4042
+ dragOffsetX = e.clientX - rect.left;
4043
+ dragOffsetY = e.clientY - rect.top;
4044
+ panel.style.zIndex = '9999'; // Bring to front
4045
+ });
4046
+
4047
+ document.addEventListener('mousemove', (e) => {
4048
+ if (!isDragging || !panel.parentElement) return;
4049
+ panel.style.left = (e.clientX - dragOffsetX) + 'px';
4050
+ panel.style.top = (e.clientY - dragOffsetY) + 'px';
4051
+ panel.style.right = 'auto'; // Remove right constraint when dragging
4052
+ });
4053
+
4054
+ document.addEventListener('mouseup', () => {
4055
+ isDragging = false;
4056
+ });
4033
4057
 
4034
4058
  const titles = {
4035
4059
  'copilot-panel': '✨ AI Copilot',
@@ -5243,6 +5267,6 @@
5243
5267
  </div>
5244
5268
  </div>
5245
5269
 
5246
- <span id="version-badge" style="position:fixed;bottom:42px;left:50%;transform:translateX(-50%);z-index:999;font-size:0.9rem;color:rgba(255,255,255,0.9);letter-spacing:0.1em;white-space:nowrap;padding:6px 16px;user-select:all;pointer-events:auto;font-family:monospace;font-weight:700;background:rgba(0,0,0,0.7);border:1px solid rgba(88,166,255,0.4);border-radius:6px;text-shadow:0 1px 3px rgba(0,0,0,0.5);" title="cycleCAD version">cycleCAD v1.0.4</span>
5270
+ <span id="version-badge" style="position:fixed;bottom:42px;left:50%;transform:translateX(-50%);z-index:999;font-size:0.9rem;color:rgba(255,255,255,0.9);letter-spacing:0.1em;white-space:nowrap;padding:6px 16px;user-select:all;pointer-events:auto;font-family:monospace;font-weight:700;background:rgba(0,0,0,0.7);border:1px solid rgba(88,166,255,0.4);border-radius:6px;text-shadow:0 1px 3px rgba(0,0,0,0.5);" title="cycleCAD version">cycleCAD v1.0.5</span>
5247
5271
  </body>
5248
5272
  </html>
@@ -349,12 +349,17 @@ export function createPrimitive(type, params = {}, options = {}) {
349
349
  const { material = 'steel' } = options;
350
350
  let geometry;
351
351
 
352
+ // Scale factor: AI copilot provides dimensions in millimeters, but we render at 1:1 scene units
353
+ // For a 100mm cube to look reasonable in viewport, scale down by 1.0 (1:1 scale)
354
+ // Most CAD systems use 1 scene unit = 1 mm
355
+ const SCALE = 1.0;
356
+
352
357
  switch (type) {
353
358
  case 'box':
354
359
  geometry = new THREE.BoxGeometry(
355
- params.width || 1,
356
- params.height || 1,
357
- params.depth || 1,
360
+ (params.width || 10) * SCALE,
361
+ (params.height || 10) * SCALE,
362
+ (params.depth || 10) * SCALE,
358
363
  params.widthSegments || 1,
359
364
  params.heightSegments || 1,
360
365
  params.depthSegments || 1
@@ -363,9 +368,9 @@ export function createPrimitive(type, params = {}, options = {}) {
363
368
 
364
369
  case 'cylinder':
365
370
  geometry = new THREE.CylinderGeometry(
366
- params.radius || 1,
367
- params.radius || 1,
368
- params.height || 2,
371
+ (params.radius || 10) * SCALE,
372
+ (params.radius || 10) * SCALE,
373
+ (params.height || 20) * SCALE,
369
374
  params.segments || 32,
370
375
  1,
371
376
  params.openEnded || false
@@ -374,7 +379,7 @@ export function createPrimitive(type, params = {}, options = {}) {
374
379
 
375
380
  case 'sphere':
376
381
  geometry = new THREE.SphereGeometry(
377
- params.radius || 1,
382
+ (params.radius || 10) * SCALE,
378
383
  params.segments || 32,
379
384
  params.segments || 32
380
385
  );
@@ -382,26 +387,42 @@ export function createPrimitive(type, params = {}, options = {}) {
382
387
 
383
388
  case 'cone':
384
389
  geometry = new THREE.ConeGeometry(
385
- params.bottomRadius || 1,
386
- params.height || 2,
390
+ (params.bottomRadius || 10) * SCALE,
391
+ (params.height || 20) * SCALE,
387
392
  params.segments || 32
388
393
  );
389
394
  break;
390
395
 
391
396
  case 'torus':
392
397
  geometry = new THREE.TorusGeometry(
393
- params.radius || 1,
394
- params.tube || 0.4,
398
+ (params.radius || 10) * SCALE,
399
+ (params.tube || 4) * SCALE,
395
400
  params.radialSegments || 16,
396
401
  params.tubeSegments || 100
397
402
  );
398
403
  break;
399
404
 
405
+ case 'hole': {
406
+ // Create a cylinder for hole preview (visual aid — actual hole subtraction happens in boolean operations)
407
+ // Used by feature.hole commands from AI copilot
408
+ const holeRadius = (params.radius || 5) * SCALE;
409
+ const holeDepth = (params.depth || 20) * SCALE;
410
+ geometry = new THREE.CylinderGeometry(
411
+ holeRadius,
412
+ holeRadius,
413
+ holeDepth,
414
+ 16,
415
+ 1,
416
+ false
417
+ );
418
+ break;
419
+ }
420
+
400
421
  case 'bracket': {
401
422
  // L-shaped bracket from width, height, thickness
402
- const bw = params.width || 80;
403
- const bh = params.height || 40;
404
- const bt = params.thickness || 5;
423
+ const bw = (params.width || 80) * SCALE;
424
+ const bh = (params.height || 40) * SCALE;
425
+ const bt = (params.thickness || 5) * SCALE;
405
426
  const shape = new THREE.Shape();
406
427
  shape.moveTo(0, 0);
407
428
  shape.lineTo(bw, 0);
@@ -417,9 +438,9 @@ export function createPrimitive(type, params = {}, options = {}) {
417
438
 
418
439
  case 'flange': {
419
440
  // Annular flange: outer ring with center hole
420
- const fo = (params.outerDiameter || params.outerRadius * 2 || 60) / 2;
421
- const fi = (params.innerDiameter || params.innerRadius * 2 || 20) / 2;
422
- const fh = params.height || params.thickness || 10;
441
+ const fo = ((params.outerDiameter || params.outerRadius * 2 || 60) / 2) * SCALE;
442
+ const fi = ((params.innerDiameter || params.innerRadius * 2 || 20) / 2) * SCALE;
443
+ const fh = (params.height || params.thickness || 10) * SCALE;
423
444
  const outerShape = new THREE.Shape();
424
445
  outerShape.absarc(0, 0, fo, 0, Math.PI * 2, false);
425
446
  const holePath = new THREE.Path();
@@ -431,9 +452,9 @@ export function createPrimitive(type, params = {}, options = {}) {
431
452
  }
432
453
 
433
454
  case 'washer': {
434
- const wo = (params.outerDiameter || 20) / 2;
435
- const wi = (params.innerDiameter || 10) / 2;
436
- const wt = params.thickness || 2;
455
+ const wo = ((params.outerDiameter || 20) / 2) * SCALE;
456
+ const wi = ((params.innerDiameter || 10) / 2) * SCALE;
457
+ const wt = (params.thickness || 2) * SCALE;
437
458
  const wShape = new THREE.Shape();
438
459
  wShape.absarc(0, 0, wo, 0, Math.PI * 2, false);
439
460
  const wHole = new THREE.Path();
@@ -445,9 +466,9 @@ export function createPrimitive(type, params = {}, options = {}) {
445
466
  }
446
467
 
447
468
  case 'spacer': {
448
- const so = (params.outerDiameter || params.diameter || 15) / 2;
449
- const si = (params.innerDiameter || params.holeDiameter || 6) / 2;
450
- const sh = params.height || params.length || 20;
469
+ const so = (((params.outerDiameter || params.diameter || 15) / 2) * SCALE);
470
+ const si = (((params.innerDiameter || params.holeDiameter || 6) / 2) * SCALE);
471
+ const sh = (params.height || params.length || 20) * SCALE;
451
472
  const sShape = new THREE.Shape();
452
473
  sShape.absarc(0, 0, so, 0, Math.PI * 2, false);
453
474
  const sHole = new THREE.Path();
@@ -460,9 +481,9 @@ export function createPrimitive(type, params = {}, options = {}) {
460
481
 
461
482
  case 'gear': {
462
483
  // Simple spur gear approximation
463
- const gr = params.radius || params.diameter / 2 || 30;
484
+ const gr = ((params.radius || params.diameter / 2 || 30) * SCALE);
464
485
  const gt = params.teeth || 20;
465
- const gd = params.depth || params.thickness || 10;
486
+ const gd = (params.depth || params.thickness || 10) * SCALE;
466
487
  const toothH = gr * 0.15;
467
488
  const gShape = new THREE.Shape();
468
489
  for (let i = 0; i < gt; i++) {
@@ -482,9 +503,9 @@ export function createPrimitive(type, params = {}, options = {}) {
482
503
  }
483
504
 
484
505
  case 'plate': {
485
- const pw = params.width || 100;
486
- const ph = params.height || params.depth || 50;
487
- const pt = params.thickness || 5;
506
+ const pw = (params.width || 100) * SCALE;
507
+ const ph = (params.height || params.depth || 50) * SCALE;
508
+ const pt = (params.thickness || 5) * SCALE;
488
509
  geometry = new THREE.BoxGeometry(pw, pt, ph);
489
510
  break;
490
511
  }
@@ -493,8 +514,8 @@ export function createPrimitive(type, params = {}, options = {}) {
493
514
  // Fallback: treat unknown as a box with available dimensions
494
515
  console.warn(`Unknown primitive type "${type}" — creating box fallback`);
495
516
  geometry = new THREE.BoxGeometry(
496
- params.width || params.diameter || 50,
497
- params.height || params.thickness || 50,
517
+ (params.width || params.diameter || 50) * SCALE,
518
+ (params.height || params.thickness || 50) * SCALE,
498
519
  params.depth || params.thickness || 50
499
520
  );
500
521
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyclecad",
3
- "version": "1.0.4",
3
+ "version": "1.0.5",
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": {