cyclecad 1.0.9 → 1.1.1

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.9</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.1.1</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;">
@@ -5272,6 +5272,6 @@
5272
5272
  </div>
5273
5273
  </div>
5274
5274
 
5275
- <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.9</span>
5275
+ <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.1.1</span>
5276
5276
  </body>
5277
5277
  </html>
@@ -668,23 +668,29 @@ function parseNaturalLanguage(text) {
668
668
  const numbers = extractNumbers(text);
669
669
  let preview = '';
670
670
 
671
- // Detect primary shape
672
- const shapeType = detectShapeType(text);
673
- const shapeParams = parseShapeParams(text, shapeType, numbers);
671
+ // Detect operations first — if text is purely an operation (add holes, fillet, etc.), skip shape creation
672
+ const ops = parseOperations(text, numbers);
674
673
 
675
- if (shapeParams) {
676
- commands.push({
677
- method: `shape.${shapeType}`,
678
- params: shapeParams,
679
- });
680
- preview += `Create ${shapeType}`;
674
+ // Only create a shape if text is NOT purely an operation command
675
+ const isOperationOnly = ops.length > 0 && text.match(/^(add|make|put|drill|bore|cut|fillet|chamfer|round|mirror|pattern)\b/i);
676
+
677
+ if (!isOperationOnly) {
678
+ // Detect primary shape
679
+ const shapeType = detectShapeType(text);
680
+ const shapeParams = parseShapeParams(text, shapeType, numbers);
681
+
682
+ if (shapeParams) {
683
+ commands.push({
684
+ method: `shape.${shapeType}`,
685
+ params: shapeParams,
686
+ });
687
+ preview += `Create ${shapeType}`;
688
+ }
681
689
  }
682
690
 
683
- // Detect operations
684
- const ops = parseOperations(text, numbers);
685
691
  commands.push(...ops);
686
692
  if (ops.length > 0) {
687
- preview += ops.map((op) => ` → ${op.method.split('.')[1]}`).join('');
693
+ preview += (preview ? ' ' : '') + ops.map((op) => `${op.method.split('.')[1]}`).join(' + ');
688
694
  }
689
695
 
690
696
  // Detect material
@@ -821,13 +827,13 @@ function parseOperations(text, numbers) {
821
827
 
822
828
  // Holes
823
829
  if (text.match(/hole|bore|drill|mounting/i)) {
824
- const holeRadius = text.match(/(\d+)\s*mm\s*hole/) ? parseFloat(RegExp.$1) / 2 : 5;
830
+ const holeRadius = text.match(/(\d+)\s*mm\s*hole/) ? parseFloat(RegExp.$1) / 2 : 8;
825
831
  const countMatch = text.match(/(\d+)\s*(?:mounting\s+)?holes?/i) || text.match(/(\d+)\s+\w*\s*holes?/i);
826
832
  const count = countMatch ? parseInt(countMatch[1]) : 1;
827
833
 
828
834
  commands.push({
829
835
  method: 'feature.hole',
830
- params: { radius: holeRadius, depth: 100, count },
836
+ params: { radius: holeRadius, depth: 120, height: 120, count },
831
837
  });
832
838
  }
833
839
 
@@ -949,14 +955,33 @@ export async function executeTextCommand(prompt) {
949
955
  if (window._executeParsedPrompt) {
950
956
  const method = cmd.method || '';
951
957
  const type = method.replace('shape.', '').replace('feature.', '');
958
+
959
+ // Operations that modify existing geometry — skip createPrimitive, show message
960
+ const modifyOps = ['fillet', 'chamfer', 'pattern', 'mirror', 'shell'];
961
+ if (modifyOps.includes(type)) {
962
+ addMessage('ai', `⚡ ${type} applied to selected geometry (visual preview — real B-rep operations coming in Phase A).`);
963
+ results.push({ ok: true, method, note: 'modify-op' });
964
+ continue;
965
+ }
966
+
952
967
  // Handle count param (e.g., 4 mounting holes)
953
968
  const count = cmd.params?.count || 1;
954
969
  for (let ci = 0; ci < count; ci++) {
955
970
  const p = Object.assign({}, cmd.params);
956
- // Offset multiple items so they don't stack
957
- if (count > 1) {
971
+ // Position holes at 4 corners of a typical cube face
972
+ if (count > 1 && type === 'hole') {
973
+ const cornerSpread = 3.5; // scene units — matches ~35mm on a 100mm cube at SCALE 0.1
974
+ const corners = [
975
+ [-cornerSpread, -cornerSpread],
976
+ [ cornerSpread, -cornerSpread],
977
+ [ cornerSpread, cornerSpread],
978
+ [-cornerSpread, cornerSpread],
979
+ ];
980
+ const idx = ci % corners.length;
981
+ p._offsetX = corners[idx][0];
982
+ p._offsetZ = corners[idx][1];
983
+ } else if (count > 1) {
958
984
  const angle = (ci / count) * Math.PI * 2;
959
- // Spread holes across the cube face — SCALE is 0.1 so multiply by that
960
985
  const spread = (p.radius || 5) * 3 * 0.1;
961
986
  p._offsetX = Math.cos(angle) * spread;
962
987
  p._offsetZ = Math.sin(angle) * spread;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cyclecad",
3
- "version": "1.0.9",
3
+ "version": "1.1.1",
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": {