cyclecad 0.1.4 → 0.1.7
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/CLAUDE.md +20 -9
- package/app/index.html +451 -3
- package/app/js/advanced-ops.js +762 -0
- package/app/js/assembly.js +1102 -0
- package/app/js/constraint-solver.js +1046 -0
- package/app/js/dxf-export.js +1173 -0
- package/app/js/viewport.js +83 -0
- package/app/mobile.html +1276 -0
- package/package.json +1 -1
- package/DUO-MANIFEST-README.md +0 -233
- package/app/duo-manifest-demo.html +0 -337
- package/app/duo-manifest.json +0 -7375
package/app/js/viewport.js
CHANGED
|
@@ -29,6 +29,9 @@ let isAnimating = false;
|
|
|
29
29
|
let gridHelper = null;
|
|
30
30
|
let axisLines = null;
|
|
31
31
|
let referencePlanes = {};
|
|
32
|
+
let groundPlane = null;
|
|
33
|
+
let selectionOutline = null;
|
|
34
|
+
let hemiLight = null;
|
|
32
35
|
|
|
33
36
|
// Camera animation state
|
|
34
37
|
let cameraAnimationState = {
|
|
@@ -181,6 +184,10 @@ function setupLighting() {
|
|
|
181
184
|
const fillLight = new THREE.DirectionalLight(COLORS.fill, 0.3);
|
|
182
185
|
fillLight.position.set(-100, 50, -100);
|
|
183
186
|
scene.add(fillLight);
|
|
187
|
+
|
|
188
|
+
// Hemisphere light for natural environment feel (sky blue → ground grey)
|
|
189
|
+
hemiLight = new THREE.HemisphereLight(0x4488cc, 0x222222, 0.25);
|
|
190
|
+
scene.add(hemiLight);
|
|
184
191
|
}
|
|
185
192
|
|
|
186
193
|
// ============================================================================
|
|
@@ -238,6 +245,16 @@ function setupGridAndOrigin() {
|
|
|
238
245
|
axisLines = new THREE.LineSegments(axisGeometry, axisMaterial);
|
|
239
246
|
scene.add(axisLines);
|
|
240
247
|
|
|
248
|
+
// Ground shadow plane (invisible but receives shadows)
|
|
249
|
+
const groundGeom = new THREE.PlaneGeometry(GRID_SIZE * 2, GRID_SIZE * 2);
|
|
250
|
+
const groundMat = new THREE.ShadowMaterial({ opacity: 0.15 });
|
|
251
|
+
groundPlane = new THREE.Mesh(groundGeom, groundMat);
|
|
252
|
+
groundPlane.rotation.x = -Math.PI / 2;
|
|
253
|
+
groundPlane.position.y = -0.01; // Just below grid to avoid z-fighting
|
|
254
|
+
groundPlane.receiveShadow = true;
|
|
255
|
+
groundPlane.userData.isGround = true;
|
|
256
|
+
scene.add(groundPlane);
|
|
257
|
+
|
|
241
258
|
// Create reference planes (semi-transparent quads)
|
|
242
259
|
createReferencePlanes();
|
|
243
260
|
}
|
|
@@ -426,6 +443,13 @@ function calculateOptimalDistance() {
|
|
|
426
443
|
*/
|
|
427
444
|
export function addToScene(object) {
|
|
428
445
|
if (scene) {
|
|
446
|
+
// Auto-enable shadows on meshes
|
|
447
|
+
object.traverse((child) => {
|
|
448
|
+
if (child.isMesh) {
|
|
449
|
+
child.castShadow = true;
|
|
450
|
+
child.receiveShadow = true;
|
|
451
|
+
}
|
|
452
|
+
});
|
|
429
453
|
scene.add(object);
|
|
430
454
|
}
|
|
431
455
|
}
|
|
@@ -516,6 +540,62 @@ export function toggleWireframe(enabled) {
|
|
|
516
540
|
}
|
|
517
541
|
}
|
|
518
542
|
|
|
543
|
+
// ============================================================================
|
|
544
|
+
// Selection Highlighting
|
|
545
|
+
// ============================================================================
|
|
546
|
+
|
|
547
|
+
/**
|
|
548
|
+
* Highlight a mesh with a colored outline/glow effect
|
|
549
|
+
* @param {THREE.Mesh} mesh - Mesh to highlight
|
|
550
|
+
* @param {number} color - Highlight color (default: blue)
|
|
551
|
+
*/
|
|
552
|
+
export function highlightMesh(mesh, color = 0x58a6ff) {
|
|
553
|
+
// Remove existing highlight
|
|
554
|
+
clearHighlight();
|
|
555
|
+
|
|
556
|
+
if (!mesh || !mesh.geometry) return;
|
|
557
|
+
|
|
558
|
+
// Create outline using scaled clone with BackSide rendering
|
|
559
|
+
const outlineMat = new THREE.MeshBasicMaterial({
|
|
560
|
+
color: color,
|
|
561
|
+
side: THREE.BackSide,
|
|
562
|
+
transparent: true,
|
|
563
|
+
opacity: 0.4,
|
|
564
|
+
});
|
|
565
|
+
|
|
566
|
+
selectionOutline = new THREE.Mesh(mesh.geometry.clone(), outlineMat);
|
|
567
|
+
selectionOutline.scale.copy(mesh.scale).multiplyScalar(1.03);
|
|
568
|
+
selectionOutline.position.copy(mesh.position);
|
|
569
|
+
selectionOutline.rotation.copy(mesh.rotation);
|
|
570
|
+
selectionOutline.userData.isHighlight = true;
|
|
571
|
+
scene.add(selectionOutline);
|
|
572
|
+
}
|
|
573
|
+
|
|
574
|
+
/**
|
|
575
|
+
* Clear the current selection highlight
|
|
576
|
+
*/
|
|
577
|
+
export function clearHighlight() {
|
|
578
|
+
if (selectionOutline) {
|
|
579
|
+
scene.remove(selectionOutline);
|
|
580
|
+
if (selectionOutline.geometry) selectionOutline.geometry.dispose();
|
|
581
|
+
if (selectionOutline.material) selectionOutline.material.dispose();
|
|
582
|
+
selectionOutline = null;
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
586
|
+
/**
|
|
587
|
+
* Enable castShadow on a mesh (call after adding to scene)
|
|
588
|
+
* @param {THREE.Object3D} object - Object to enable shadows on
|
|
589
|
+
*/
|
|
590
|
+
export function enableShadows(object) {
|
|
591
|
+
object.traverse((child) => {
|
|
592
|
+
if (child.isMesh) {
|
|
593
|
+
child.castShadow = true;
|
|
594
|
+
child.receiveShadow = true;
|
|
595
|
+
}
|
|
596
|
+
});
|
|
597
|
+
}
|
|
598
|
+
|
|
519
599
|
// ============================================================================
|
|
520
600
|
// Accessors
|
|
521
601
|
// ============================================================================
|
|
@@ -664,4 +744,7 @@ export function dispose() {
|
|
|
664
744
|
gridHelper = null;
|
|
665
745
|
axisLines = null;
|
|
666
746
|
referencePlanes = {};
|
|
747
|
+
groundPlane = null;
|
|
748
|
+
selectionOutline = null;
|
|
749
|
+
hemiLight = null;
|
|
667
750
|
}
|