helixmind 0.2.15 → 0.2.17
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.
Potentially problematic release.
This version of helixmind might be problematic. Click here for more details.
- package/LICENSE +2 -2
- package/README.md +34 -107
- package/dist/cli/agent/loop.d.ts +2 -0
- package/dist/cli/agent/loop.d.ts.map +1 -1
- package/dist/cli/agent/loop.js +17 -4
- package/dist/cli/agent/loop.js.map +1 -1
- package/dist/cli/brain/template.d.ts.map +1 -1
- package/dist/cli/brain/template.js +201 -181
- package/dist/cli/brain/template.js.map +1 -1
- package/dist/cli/commands/chat.d.ts.map +1 -1
- package/dist/cli/commands/chat.js +146 -75
- package/dist/cli/commands/chat.js.map +1 -1
- package/dist/cli/index.js +1 -1
- package/dist/cli/index.js.map +1 -1
- package/dist/cli/ui/tool-output.d.ts +5 -0
- package/dist/cli/ui/tool-output.d.ts.map +1 -1
- package/dist/cli/ui/tool-output.js +23 -0
- package/dist/cli/ui/tool-output.js.map +1 -1
- package/package.json +2 -2
|
@@ -595,21 +595,23 @@ scene.fog = new THREE.FogExp2(0x050510, 0.00005); // Reduced fog for clearer vis
|
|
|
595
595
|
const camera = new THREE.PerspectiveCamera(55, innerWidth / innerHeight, 0.1, 10000);
|
|
596
596
|
camera.position.set(0, 200, 1200); // Centered on force-directed graph
|
|
597
597
|
|
|
598
|
-
const renderer = new THREE.WebGLRenderer({ antialias:
|
|
598
|
+
const renderer = new THREE.WebGLRenderer({ antialias: false, alpha: false, powerPreference: 'high-performance' });
|
|
599
599
|
renderer.setSize(innerWidth, innerHeight);
|
|
600
|
-
renderer.setPixelRatio(
|
|
600
|
+
renderer.setPixelRatio(1);
|
|
601
601
|
renderer.toneMapping = THREE.ACESFilmicToneMapping;
|
|
602
602
|
renderer.toneMappingExposure = 1.2;
|
|
603
603
|
document.body.prepend(renderer.domElement);
|
|
604
604
|
|
|
605
|
-
// =========== POST-PROCESSING (Bloom) ===========
|
|
605
|
+
// =========== POST-PROCESSING (Bloom at half resolution) ===========
|
|
606
|
+
const bloomW = Math.round(innerWidth / 2);
|
|
607
|
+
const bloomH = Math.round(innerHeight / 2);
|
|
606
608
|
const composer = new EffectComposer(renderer);
|
|
607
609
|
composer.addPass(new RenderPass(scene, camera));
|
|
608
610
|
const bloomPass = new UnrealBloomPass(
|
|
609
|
-
new THREE.Vector2(
|
|
610
|
-
0.
|
|
611
|
-
0.
|
|
612
|
-
0.
|
|
611
|
+
new THREE.Vector2(bloomW, bloomH),
|
|
612
|
+
0.6, // strength (reduced)
|
|
613
|
+
0.3, // radius
|
|
614
|
+
0.7 // threshold (higher = fewer objects bloom)
|
|
613
615
|
);
|
|
614
616
|
composer.addPass(bloomPass);
|
|
615
617
|
|
|
@@ -636,9 +638,9 @@ const fillLight = new THREE.PointLight(0x00FF88, 0.4, 3000);
|
|
|
636
638
|
fillLight.position.set(400, 100, -300);
|
|
637
639
|
scene.add(fillLight);
|
|
638
640
|
|
|
639
|
-
// =========== BACKGROUND PARTICLES ===========
|
|
641
|
+
// =========== BACKGROUND PARTICLES (reduced count) ===========
|
|
640
642
|
const starGeo = new THREE.BufferGeometry();
|
|
641
|
-
const starCount =
|
|
643
|
+
const starCount = 800;
|
|
642
644
|
const starPos = new Float32Array(starCount * 3);
|
|
643
645
|
for (let i = 0; i < starCount * 3; i++) starPos[i] = (Math.random() - 0.5) * 8000;
|
|
644
646
|
starGeo.setAttribute('position', new THREE.BufferAttribute(starPos, 3));
|
|
@@ -692,13 +694,21 @@ class BrainManager {
|
|
|
692
694
|
// Connected nodes will pull together, unconnected repel — organic clusters form naturally
|
|
693
695
|
const SPREAD = 600; // Initial scatter radius
|
|
694
696
|
|
|
697
|
+
// Shared geometries — reuse instead of creating per node
|
|
698
|
+
const sharedIcoGeo = new THREE.IcosahedronGeometry(1, 1); // unit size, detail 1 (low poly)
|
|
699
|
+
const sharedOctGeo = new THREE.OctahedronGeometry(1, 1);
|
|
700
|
+
const sharedHitGeo = new THREE.SphereGeometry(1, 6, 4); // minimal segments
|
|
701
|
+
const sharedRingGeo = new THREE.RingGeometry(1, 1.6, 16); // reduced segments
|
|
702
|
+
const sharedWaveGeo = new THREE.RingGeometry(1, 1.1, 16);
|
|
703
|
+
const sharedWireGeo = new THREE.OctahedronGeometry(1, 0);
|
|
704
|
+
|
|
695
705
|
data.nodes.forEach((node, i) => {
|
|
696
706
|
const isWeb = node.level === 6;
|
|
697
707
|
|
|
698
708
|
// Random spherical distribution as starting positions
|
|
699
|
-
const phi = Math.acos(2 * Math.random() - 1);
|
|
700
|
-
const theta = Math.random() * Math.PI * 2;
|
|
701
|
-
const r = SPREAD * (0.3 + Math.random() * 0.7);
|
|
709
|
+
const phi = Math.acos(2 * Math.random() - 1);
|
|
710
|
+
const theta = Math.random() * Math.PI * 2;
|
|
711
|
+
const r = SPREAD * (0.3 + Math.random() * 0.7);
|
|
702
712
|
const x = r * Math.sin(phi) * Math.cos(theta);
|
|
703
713
|
const y = r * Math.sin(phi) * Math.sin(theta);
|
|
704
714
|
const z = r * Math.cos(phi);
|
|
@@ -710,66 +720,65 @@ class BrainManager {
|
|
|
710
720
|
const size = LEVEL_SIZES[node.level] || 3;
|
|
711
721
|
const color = new THREE.Color(LEVEL_COLORS[node.level] || 0x00FFFF);
|
|
712
722
|
|
|
713
|
-
// Core
|
|
714
|
-
const coreGeo = isWeb
|
|
715
|
-
? new THREE.OctahedronGeometry(size, 2)
|
|
716
|
-
: new THREE.IcosahedronGeometry(size, 3);
|
|
723
|
+
// Core mesh — shared geometry, scaled per node
|
|
717
724
|
const coreMat = new THREE.MeshStandardMaterial({
|
|
718
725
|
color, emissive: color, emissiveIntensity: LEVEL_GLOW[node.level] || 0.6,
|
|
719
726
|
roughness: isWeb ? 0.1 : 0.15,
|
|
720
727
|
metalness: isWeb ? 0.9 : 0.7,
|
|
721
728
|
transparent: true, opacity: 0.95,
|
|
722
729
|
});
|
|
723
|
-
const coreMesh = new THREE.Mesh(
|
|
730
|
+
const coreMesh = new THREE.Mesh(isWeb ? sharedOctGeo : sharedIcoGeo, coreMat);
|
|
731
|
+
coreMesh.scale.set(size, size, size);
|
|
724
732
|
coreMesh.position.copy(node._pos);
|
|
725
733
|
coreMesh.userData = node;
|
|
726
734
|
coreMesh.userData._color = color.clone();
|
|
735
|
+
coreMesh.userData._baseSize = size;
|
|
727
736
|
this.nodeGroup.add(coreMesh);
|
|
728
737
|
this.nodeMeshes.push(coreMesh);
|
|
729
738
|
|
|
730
|
-
//
|
|
731
|
-
const hitGeo = new THREE.SphereGeometry(size * 3, 8, 6);
|
|
739
|
+
// Hit detection — shared geometry, scaled
|
|
732
740
|
const hitMat = new THREE.MeshBasicMaterial({ visible: false });
|
|
733
|
-
const hitMesh = new THREE.Mesh(
|
|
741
|
+
const hitMesh = new THREE.Mesh(sharedHitGeo, hitMat);
|
|
742
|
+
hitMesh.scale.set(size * 3, size * 3, size * 3);
|
|
734
743
|
hitMesh.position.copy(node._pos);
|
|
735
744
|
hitMesh.userData = node;
|
|
736
745
|
hitMesh.userData._coreMesh = coreMesh;
|
|
737
746
|
this.nodeGroup.add(hitMesh);
|
|
738
747
|
this.nodeHitMeshes.push(hitMesh);
|
|
739
748
|
|
|
740
|
-
//
|
|
749
|
+
// Glow ring — shared geometry, scaled
|
|
741
750
|
const ringScale = isWeb ? 2.8 : 1.4;
|
|
742
|
-
const ringOuter = isWeb ? 3.5 : 2.2;
|
|
743
|
-
const ringGeo = new THREE.RingGeometry(size * ringScale, size * ringOuter, 32);
|
|
744
751
|
const ringMat = new THREE.MeshBasicMaterial({
|
|
745
752
|
color, transparent: true, opacity: isWeb ? 0.12 : 0.08, side: THREE.DoubleSide,
|
|
746
753
|
});
|
|
747
|
-
const ring = new THREE.Mesh(
|
|
754
|
+
const ring = new THREE.Mesh(sharedRingGeo, ringMat);
|
|
755
|
+
ring.scale.set(size * ringScale, size * ringScale, size * ringScale);
|
|
748
756
|
ring.position.copy(node._pos);
|
|
749
757
|
ring.userData = { nodeIndex: i };
|
|
750
758
|
this.nodeGroup.add(ring);
|
|
751
759
|
this.glowRings.push(ring);
|
|
752
760
|
|
|
753
|
-
// L6 Web nodes
|
|
761
|
+
// L6 Web nodes: signal wave rings (reduced to 2) + wireframe shell
|
|
754
762
|
if (isWeb) {
|
|
755
|
-
for (let w = 0; w <
|
|
756
|
-
const
|
|
763
|
+
for (let w = 0; w < 2; w++) {
|
|
764
|
+
const waveScale = size * (3 + w * 2);
|
|
757
765
|
const waveMat = new THREE.MeshBasicMaterial({
|
|
758
766
|
color: 0xFFAA00, transparent: true, opacity: 0, side: THREE.DoubleSide,
|
|
759
767
|
});
|
|
760
|
-
const waveMesh = new THREE.Mesh(
|
|
768
|
+
const waveMesh = new THREE.Mesh(sharedWaveGeo, waveMat);
|
|
769
|
+
waveMesh.scale.set(waveScale, waveScale, waveScale);
|
|
761
770
|
waveMesh.position.copy(node._pos);
|
|
762
771
|
waveMesh.userData = { nodeIndex: i, waveIndex: w, _startTime: 0 };
|
|
763
772
|
this.nodeGroup.add(waveMesh);
|
|
764
773
|
this.webSignalRings.push(waveMesh);
|
|
765
774
|
}
|
|
766
775
|
|
|
767
|
-
// Wireframe outer shell for L6
|
|
768
|
-
const wireGeo = new THREE.OctahedronGeometry(size * 1.8, 1);
|
|
769
776
|
const wireMat = new THREE.MeshBasicMaterial({
|
|
770
777
|
color: 0xFFAA00, wireframe: true, transparent: true, opacity: 0.15,
|
|
771
778
|
});
|
|
772
|
-
const wireMesh = new THREE.Mesh(
|
|
779
|
+
const wireMesh = new THREE.Mesh(sharedWireGeo, wireMat);
|
|
780
|
+
const ws = size * 1.8;
|
|
781
|
+
wireMesh.scale.set(ws, ws, ws);
|
|
773
782
|
wireMesh.position.copy(node._pos);
|
|
774
783
|
wireMesh.userData = { nodeIndex: i, isWireShell: true };
|
|
775
784
|
this.nodeGroup.add(wireMesh);
|
|
@@ -835,124 +844,129 @@ class BrainManager {
|
|
|
835
844
|
simulateForces() {
|
|
836
845
|
if (!this.simActive) return;
|
|
837
846
|
if (this.simSteps <= 0) { this.simActive = false; return; }
|
|
838
|
-
this.simSteps--;
|
|
839
847
|
|
|
848
|
+
// Run multiple sim steps per frame to converge faster (less total frames with sim overhead)
|
|
849
|
+
const stepsPerFrame = Math.min(4, this.simSteps);
|
|
840
850
|
const nodes = BRAIN_DATA.nodes;
|
|
841
|
-
const
|
|
842
|
-
const
|
|
843
|
-
const
|
|
851
|
+
const n = nodes.length;
|
|
852
|
+
const repulsion = 18000;
|
|
853
|
+
const edgeAttraction = 0.003;
|
|
854
|
+
const edgeIdealLen = 80;
|
|
844
855
|
const damping = 0.82;
|
|
845
|
-
const centerPull = 0.0003;
|
|
856
|
+
const centerPull = 0.0003;
|
|
846
857
|
const cutoff = 800;
|
|
847
|
-
|
|
848
|
-
// Spatial grid for O(n) repulsion instead of O(n²)
|
|
858
|
+
const cutoff2 = cutoff * cutoff;
|
|
849
859
|
const cellSize = cutoff;
|
|
850
|
-
const grid = new Map();
|
|
851
|
-
for (let i = 0; i < nodes.length; i++) {
|
|
852
|
-
const cx = Math.floor(nodes[i]._pos.x / cellSize);
|
|
853
|
-
const cy = Math.floor(nodes[i]._pos.y / cellSize);
|
|
854
|
-
const cz = Math.floor(nodes[i]._pos.z / cellSize);
|
|
855
|
-
const key = cx + ',' + cy + ',' + cz;
|
|
856
|
-
if (!grid.has(key)) grid.set(key, []);
|
|
857
|
-
grid.get(key).push(i);
|
|
858
|
-
}
|
|
859
860
|
|
|
860
|
-
|
|
861
|
-
|
|
862
|
-
|
|
863
|
-
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
875
|
-
|
|
876
|
-
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
|
|
880
|
-
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
861
|
+
for (let step = 0; step < stepsPerFrame; step++) {
|
|
862
|
+
this.simSteps--;
|
|
863
|
+
|
|
864
|
+
// Spatial grid — reuse object for less GC
|
|
865
|
+
const grid = new Map();
|
|
866
|
+
for (let i = 0; i < n; i++) {
|
|
867
|
+
const p = nodes[i]._pos;
|
|
868
|
+
const key = (Math.floor(p.x / cellSize) * 73856093 ^ Math.floor(p.y / cellSize) * 19349663 ^ Math.floor(p.z / cellSize) * 83492791) | 0;
|
|
869
|
+
const arr = grid.get(key);
|
|
870
|
+
if (arr) arr.push(i); else grid.set(key, [i]);
|
|
871
|
+
}
|
|
872
|
+
|
|
873
|
+
// Repulsion
|
|
874
|
+
for (const [, cell] of grid) {
|
|
875
|
+
const len = cell.length;
|
|
876
|
+
for (let a = 0; a < len; a++) {
|
|
877
|
+
const i = cell[a];
|
|
878
|
+
const pi = nodes[i]._pos;
|
|
879
|
+
const vi = nodes[i]._vel;
|
|
880
|
+
for (let b = a + 1; b < len; b++) {
|
|
881
|
+
const j = cell[b];
|
|
882
|
+
const pj = nodes[j]._pos;
|
|
883
|
+
const ddx = pi.x - pj.x;
|
|
884
|
+
const ddy = pi.y - pj.y;
|
|
885
|
+
const ddz = pi.z - pj.z;
|
|
886
|
+
const dist2 = ddx*ddx + ddy*ddy + ddz*ddz;
|
|
887
|
+
if (dist2 > cutoff2) continue;
|
|
888
|
+
const dist = Math.sqrt(dist2) + 1;
|
|
889
|
+
const force = repulsion / (dist * dist);
|
|
890
|
+
const fx = (ddx / dist) * force;
|
|
891
|
+
const fy = (ddy / dist) * force;
|
|
892
|
+
const fz = (ddz / dist) * force;
|
|
893
|
+
vi.x += fx; vi.y += fy; vi.z += fz;
|
|
894
|
+
nodes[j]._vel.x -= fx; nodes[j]._vel.y -= fy; nodes[j]._vel.z -= fz;
|
|
886
895
|
}
|
|
887
896
|
}
|
|
888
897
|
}
|
|
889
|
-
}
|
|
890
|
-
|
|
891
|
-
// Edge spring forces — connected nodes attract with ideal distance
|
|
892
|
-
for (const edge of BRAIN_DATA.edges) {
|
|
893
|
-
const s = this.nodeMap.get(edge.source);
|
|
894
|
-
const t = this.nodeMap.get(edge.target);
|
|
895
|
-
if (!s || !t) continue;
|
|
896
|
-
const dx = t._pos.x - s._pos.x;
|
|
897
|
-
const dy = t._pos.y - s._pos.y;
|
|
898
|
-
const dz = t._pos.z - s._pos.z;
|
|
899
|
-
const dist = Math.sqrt(dx*dx + dy*dy + dz*dz) + 0.01;
|
|
900
|
-
// Spring: pull if > ideal, push if < ideal
|
|
901
|
-
const displacement = dist - edgeIdealLen;
|
|
902
|
-
const strength = edgeAttraction * displacement * (0.5 + edge.weight * 0.5);
|
|
903
|
-
const fx = (dx / dist) * strength;
|
|
904
|
-
const fy = (dy / dist) * strength;
|
|
905
|
-
const fz = (dz / dist) * strength;
|
|
906
|
-
s._vel.x += fx; s._vel.y += fy; s._vel.z += fz;
|
|
907
|
-
t._vel.x -= fx; t._vel.y -= fy; t._vel.z -= fz;
|
|
908
|
-
}
|
|
909
898
|
|
|
910
|
-
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
|
|
915
|
-
|
|
899
|
+
// Edge springs
|
|
900
|
+
const edges = BRAIN_DATA.edges;
|
|
901
|
+
for (let e = 0; e < edges.length; e++) {
|
|
902
|
+
const edge = edges[e];
|
|
903
|
+
const s = this.nodeMap.get(edge.source);
|
|
904
|
+
const t = this.nodeMap.get(edge.target);
|
|
905
|
+
if (!s || !t) continue;
|
|
906
|
+
const dx = t._pos.x - s._pos.x;
|
|
907
|
+
const dy = t._pos.y - s._pos.y;
|
|
908
|
+
const dz = t._pos.z - s._pos.z;
|
|
909
|
+
const dist = Math.sqrt(dx*dx + dy*dy + dz*dz) + 0.01;
|
|
910
|
+
const strength = edgeAttraction * (dist - edgeIdealLen) * (0.5 + edge.weight * 0.5);
|
|
911
|
+
const fx = (dx / dist) * strength;
|
|
912
|
+
const fy = (dy / dist) * strength;
|
|
913
|
+
const fz = (dz / dist) * strength;
|
|
914
|
+
s._vel.x += fx; s._vel.y += fy; s._vel.z += fz;
|
|
915
|
+
t._vel.x -= fx; t._vel.y -= fy; t._vel.z -= fz;
|
|
916
|
+
}
|
|
916
917
|
|
|
917
|
-
|
|
918
|
-
|
|
918
|
+
// Apply velocity + centering
|
|
919
|
+
for (let i = 0; i < n; i++) {
|
|
920
|
+
const node = nodes[i];
|
|
921
|
+
node._vel.x -= node._pos.x * centerPull;
|
|
922
|
+
node._vel.y -= node._pos.y * centerPull;
|
|
923
|
+
node._vel.z -= node._pos.z * centerPull;
|
|
924
|
+
node._vel.x *= damping; node._vel.y *= damping; node._vel.z *= damping;
|
|
925
|
+
node._pos.x += node._vel.x; node._pos.y += node._vel.y; node._pos.z += node._vel.z;
|
|
926
|
+
}
|
|
919
927
|
}
|
|
920
928
|
|
|
921
|
-
// Sync meshes
|
|
922
|
-
|
|
923
|
-
|
|
924
|
-
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
928
|
-
|
|
929
|
+
// Sync meshes (once per frame, not per sim step)
|
|
930
|
+
for (let i = 0; i < n; i++) {
|
|
931
|
+
const p = nodes[i]._pos;
|
|
932
|
+
this.nodeMeshes[i].position.set(p.x, p.y, p.z);
|
|
933
|
+
this.nodeHitMeshes[i].position.set(p.x, p.y, p.z);
|
|
934
|
+
}
|
|
935
|
+
const rings = this.glowRings;
|
|
936
|
+
for (let i = 0; i < rings.length; i++) {
|
|
937
|
+
const ni = rings[i].userData.nodeIndex;
|
|
938
|
+
if (ni < n) rings[i].position.copy(nodes[ni]._pos);
|
|
939
|
+
}
|
|
929
940
|
|
|
930
|
-
// Update
|
|
931
|
-
this.edgeLines
|
|
932
|
-
|
|
941
|
+
// Update edges
|
|
942
|
+
const lines = this.edgeLines;
|
|
943
|
+
for (let i = 0; i < lines.length; i++) {
|
|
944
|
+
const e = lines[i].userData;
|
|
933
945
|
const s = this.nodeMap.get(e.source);
|
|
934
946
|
const t = this.nodeMap.get(e.target);
|
|
935
947
|
if (s && t) {
|
|
936
|
-
const pos =
|
|
948
|
+
const pos = lines[i].geometry.attributes.position;
|
|
937
949
|
pos.setXYZ(0, s._pos.x, s._pos.y, s._pos.z);
|
|
938
950
|
pos.setXYZ(1, t._pos.x, t._pos.y, t._pos.z);
|
|
939
951
|
pos.needsUpdate = true;
|
|
940
952
|
}
|
|
941
|
-
}
|
|
953
|
+
}
|
|
942
954
|
}
|
|
943
955
|
}
|
|
944
956
|
|
|
945
957
|
const brain = new BrainManager();
|
|
946
958
|
brain.loadData(BRAIN_DATA);
|
|
947
959
|
|
|
948
|
-
// =========== RAYCASTER & INTERACTION ===========
|
|
960
|
+
// =========== RAYCASTER & INTERACTION (throttled) ===========
|
|
949
961
|
const raycaster = new THREE.Raycaster();
|
|
950
962
|
const mouse = new THREE.Vector2();
|
|
951
963
|
let hoveredMesh = null;
|
|
952
964
|
let selectedMesh = null;
|
|
953
965
|
let hoverScale = 1;
|
|
966
|
+
let lastRayTime = 0;
|
|
967
|
+
let pendingMouseEvent = null;
|
|
954
968
|
|
|
955
|
-
|
|
969
|
+
function doRaycast(e) {
|
|
956
970
|
mouse.x = (e.clientX / innerWidth) * 2 - 1;
|
|
957
971
|
mouse.y = -(e.clientY / innerHeight) * 2 + 1;
|
|
958
972
|
|
|
@@ -966,18 +980,14 @@ renderer.domElement.addEventListener('mousemove', (e) => {
|
|
|
966
980
|
const node = hitMesh.userData;
|
|
967
981
|
const coreMesh = hitMesh.userData._coreMesh;
|
|
968
982
|
|
|
969
|
-
// Unhover previous
|
|
970
983
|
if (hoveredMesh && hoveredMesh !== coreMesh) {
|
|
971
984
|
hoveredMesh.material.emissiveIntensity = LEVEL_GLOW[hoveredMesh.userData.level] || 0.6;
|
|
972
985
|
}
|
|
973
986
|
|
|
974
987
|
hoveredMesh = coreMesh;
|
|
975
988
|
renderer.domElement.style.cursor = 'pointer';
|
|
976
|
-
|
|
977
|
-
// Hover glow
|
|
978
989
|
coreMesh.material.emissiveIntensity = 1.8;
|
|
979
990
|
|
|
980
|
-
// Tooltip
|
|
981
991
|
tooltip.style.display = 'block';
|
|
982
992
|
const tx = Math.min(e.clientX + 18, innerWidth - 330);
|
|
983
993
|
const ty = Math.min(e.clientY + 18, innerHeight - 100);
|
|
@@ -997,6 +1007,16 @@ renderer.domElement.addEventListener('mousemove', (e) => {
|
|
|
997
1007
|
renderer.domElement.style.cursor = 'default';
|
|
998
1008
|
tooltip.style.display = 'none';
|
|
999
1009
|
}
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
renderer.domElement.addEventListener('mousemove', (e) => {
|
|
1013
|
+
// Throttle raycasting to max every 60ms (~16 checks/sec instead of 100+)
|
|
1014
|
+
pendingMouseEvent = e;
|
|
1015
|
+
const now = performance.now();
|
|
1016
|
+
if (now - lastRayTime < 60) return;
|
|
1017
|
+
lastRayTime = now;
|
|
1018
|
+
doRaycast(e);
|
|
1019
|
+
pendingMouseEvent = null;
|
|
1000
1020
|
});
|
|
1001
1021
|
|
|
1002
1022
|
renderer.domElement.addEventListener('click', () => {
|
|
@@ -1214,98 +1234,97 @@ document.querySelectorAll('[data-edge]').forEach(btn => {
|
|
|
1214
1234
|
});
|
|
1215
1235
|
});
|
|
1216
1236
|
|
|
1217
|
-
// =========== ANIMATION LOOP ===========
|
|
1237
|
+
// =========== ANIMATION LOOP (optimized) ===========
|
|
1218
1238
|
let frameCount = 0;
|
|
1239
|
+
let fpsFrames = 0;
|
|
1219
1240
|
let lastFpsTime = performance.now();
|
|
1220
1241
|
|
|
1221
1242
|
function animate() {
|
|
1222
1243
|
requestAnimationFrame(animate);
|
|
1244
|
+
|
|
1245
|
+
// Force simulation — only when active, skip when converged
|
|
1223
1246
|
brain.simulateForces();
|
|
1224
1247
|
controls.update();
|
|
1225
1248
|
|
|
1226
1249
|
const now = Date.now();
|
|
1227
1250
|
|
|
1228
|
-
// Node
|
|
1229
|
-
brain.nodeMeshes.forEach((m, i) => {
|
|
1230
|
-
if (selectedMesh && selectedMesh !== m) return;
|
|
1231
|
-
if (m.material.emissiveIntensity > 1.5) return; // hovered or search-highlighted
|
|
1232
|
-
|
|
1233
|
-
const lvl = m.userData.level;
|
|
1234
|
-
const base = LEVEL_GLOW[lvl] || 0.6;
|
|
1235
|
-
const speed = 0.002 + (lvl * 0.0004); // Higher levels pulse faster
|
|
1236
|
-
|
|
1237
|
-
if (lvl === 6) {
|
|
1238
|
-
// L6 Web nodes: slow rotation + stronger pulse + color shift
|
|
1239
|
-
m.rotation.y += 0.005;
|
|
1240
|
-
m.rotation.x += 0.002;
|
|
1241
|
-
const t = Math.sin(now * 0.003 + i * 0.5);
|
|
1242
|
-
m.material.emissiveIntensity = base + t * 0.35;
|
|
1243
|
-
// Color shift yellow → cyan
|
|
1244
|
-
const r = 1.0 - t * 0.5;
|
|
1245
|
-
const g = 0.67 + t * 0.16;
|
|
1246
|
-
const b = t * 0.5;
|
|
1247
|
-
m.material.emissive.setRGB(r, g, b);
|
|
1248
|
-
} else {
|
|
1249
|
-
const pulse = base + Math.sin(now * speed + i * 0.7) * 0.15;
|
|
1250
|
-
m.material.emissiveIntensity = pulse;
|
|
1251
|
-
// Subtle scale breathing — nodes "breathe"
|
|
1252
|
-
const s = 1 + Math.sin(now * 0.0015 + i * 1.1) * 0.04;
|
|
1253
|
-
m.scale.set(s, s, s);
|
|
1254
|
-
}
|
|
1255
|
-
});
|
|
1256
|
-
|
|
1257
|
-
// Glow rings face camera + gentle pulse (lookAt every 3rd frame for performance)
|
|
1251
|
+
// Node animations — every 3rd frame (imperceptible difference, 3x less work)
|
|
1258
1252
|
if (frameCount % 3 === 0) {
|
|
1259
|
-
|
|
1260
|
-
|
|
1261
|
-
|
|
1262
|
-
|
|
1263
|
-
|
|
1253
|
+
const meshes = brain.nodeMeshes;
|
|
1254
|
+
for (let i = 0; i < meshes.length; i++) {
|
|
1255
|
+
const m = meshes[i];
|
|
1256
|
+
if (selectedMesh && selectedMesh !== m) continue;
|
|
1257
|
+
if (m.material.emissiveIntensity > 1.5) continue;
|
|
1258
|
+
|
|
1259
|
+
const lvl = m.userData.level;
|
|
1260
|
+
const base = LEVEL_GLOW[lvl] || 0.6;
|
|
1261
|
+
|
|
1262
|
+
if (lvl === 6) {
|
|
1263
|
+
m.rotation.y += 0.015; // 3x per update = same visual speed
|
|
1264
|
+
m.rotation.x += 0.006;
|
|
1265
|
+
const t = Math.sin(now * 0.003 + i * 0.5);
|
|
1266
|
+
m.material.emissiveIntensity = base + t * 0.35;
|
|
1267
|
+
m.material.emissive.setRGB(1.0 - t * 0.5, 0.67 + t * 0.16, t * 0.5);
|
|
1268
|
+
} else {
|
|
1269
|
+
const speed = 0.002 + (lvl * 0.0004);
|
|
1270
|
+
m.material.emissiveIntensity = base + Math.sin(now * speed + i * 0.7) * 0.15;
|
|
1271
|
+
const bs = m.userData._baseSize || 1;
|
|
1272
|
+
const s = bs * (1 + Math.sin(now * 0.0015 + i * 1.1) * 0.04);
|
|
1273
|
+
m.scale.set(s, s, s);
|
|
1264
1274
|
}
|
|
1265
|
-
}
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
|
|
1278
|
+
// Glow rings — every 8th frame
|
|
1279
|
+
if (frameCount % 8 === 0) {
|
|
1280
|
+
const rings = brain.glowRings;
|
|
1281
|
+
for (let i = 0; i < rings.length; i++) {
|
|
1282
|
+
rings[i].lookAt(camera.position);
|
|
1283
|
+
}
|
|
1266
1284
|
}
|
|
1267
1285
|
|
|
1268
|
-
// L6
|
|
1269
|
-
if (brain.webSignalRings && frameCount %
|
|
1270
|
-
brain.webSignalRings
|
|
1286
|
+
// L6 signal waves — every 6th frame
|
|
1287
|
+
if (brain.webSignalRings && brain.webSignalRings.length > 0 && frameCount % 6 === 0) {
|
|
1288
|
+
const rings = brain.webSignalRings;
|
|
1289
|
+
for (let i = 0; i < rings.length; i++) {
|
|
1290
|
+
const ring = rings[i];
|
|
1271
1291
|
const ni = ring.userData.nodeIndex;
|
|
1272
1292
|
const wi = ring.userData.waveIndex;
|
|
1273
1293
|
if (ni < BRAIN_DATA.nodes.length) {
|
|
1274
1294
|
ring.position.copy(BRAIN_DATA.nodes[ni]._pos);
|
|
1275
1295
|
}
|
|
1276
1296
|
ring.lookAt(camera.position);
|
|
1277
|
-
|
|
1278
|
-
// Staggered wave animation: each ring pulses with offset
|
|
1279
|
-
const cycle = 3000; // ms per cycle
|
|
1297
|
+
const cycle = 3000;
|
|
1280
1298
|
const offset = wi * (cycle / 3);
|
|
1281
|
-
const t = ((now + offset) % cycle) / cycle;
|
|
1299
|
+
const t = ((now + offset) % cycle) / cycle;
|
|
1300
|
+
ring.material.opacity = (t < 0.5 ? t : 1 - t) * 0.16;
|
|
1301
|
+
const s = 1 + t * 0.6;
|
|
1302
|
+
ring.scale.set(s, s, s);
|
|
1303
|
+
}
|
|
1304
|
+
}
|
|
1282
1305
|
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
} else {
|
|
1289
|
-
ring.material.opacity = (1 - t) * 0.16;
|
|
1290
|
-
const s = 1 + t * 0.6;
|
|
1291
|
-
ring.scale.set(s, s, s);
|
|
1292
|
-
}
|
|
1293
|
-
});
|
|
1306
|
+
// Light animation — every 4th frame
|
|
1307
|
+
if (frameCount % 4 === 0) {
|
|
1308
|
+
mainLight.position.x = Math.sin(now * 0.0003) * 40;
|
|
1309
|
+
mainLight.position.z = Math.cos(now * 0.0003) * 40;
|
|
1310
|
+
rimLight.intensity = 0.6 + Math.sin(now * 0.001) * 0.25;
|
|
1294
1311
|
}
|
|
1295
1312
|
|
|
1296
|
-
//
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1313
|
+
// Process pending mousemove if throttled
|
|
1314
|
+
if (pendingMouseEvent) {
|
|
1315
|
+
doRaycast(pendingMouseEvent);
|
|
1316
|
+
pendingMouseEvent = null;
|
|
1317
|
+
}
|
|
1300
1318
|
|
|
1301
1319
|
// Render with bloom
|
|
1302
1320
|
composer.render();
|
|
1303
1321
|
|
|
1304
1322
|
// FPS counter
|
|
1305
1323
|
frameCount++;
|
|
1324
|
+
fpsFrames++;
|
|
1306
1325
|
if (now - lastFpsTime > 1000) {
|
|
1307
|
-
document.getElementById('fps-counter').textContent =
|
|
1308
|
-
|
|
1326
|
+
document.getElementById('fps-counter').textContent = fpsFrames;
|
|
1327
|
+
fpsFrames = 0;
|
|
1309
1328
|
lastFpsTime = now;
|
|
1310
1329
|
}
|
|
1311
1330
|
}
|
|
@@ -1317,6 +1336,7 @@ addEventListener('resize', () => {
|
|
|
1317
1336
|
camera.updateProjectionMatrix();
|
|
1318
1337
|
renderer.setSize(innerWidth, innerHeight);
|
|
1319
1338
|
composer.setSize(innerWidth, innerHeight);
|
|
1339
|
+
bloomPass.resolution.set(Math.round(innerWidth / 2), Math.round(innerHeight / 2));
|
|
1320
1340
|
});
|
|
1321
1341
|
|
|
1322
1342
|
// =========== WEBSOCKET LIVE UPDATES ===========
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../../src/cli/brain/template.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAAC,IAAiB;IACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAEtC,OAAO;;;;;;0CAMiC,IAAI,CAAC,IAAI,CAAC,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uCAsZxB,IAAI,CAAC,IAAI,CAAC,UAAU,iBAAiB,IAAI,CAAC,IAAI,CAAC,UAAU,eAAe,IAAI,CAAC,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,IAAI,CAAC,IAAI,CAAC,WAAW;;wCAE3L,IAAI,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;uCACpD,IAAI,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBA+JvE,QAAQ
|
|
1
|
+
{"version":3,"file":"template.js","sourceRoot":"","sources":["../../../src/cli/brain/template.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,iBAAiB,CAAC,IAAiB;IACjD,MAAM,QAAQ,GAAG,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;IAEtC,OAAO;;;;;;0CAMiC,IAAI,CAAC,IAAI,CAAC,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;uCAsZxB,IAAI,CAAC,IAAI,CAAC,UAAU,iBAAiB,IAAI,CAAC,IAAI,CAAC,UAAU,eAAe,IAAI,CAAC,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC,CAAC,CAAC,YAAY,IAAI,CAAC,IAAI,CAAC,iBAAiB,MAAM,CAAC,CAAC,CAAC,EAAE,WAAW,IAAI,CAAC,IAAI,CAAC,WAAW;;wCAE3L,IAAI,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;uCACpD,IAAI,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mBA+JvE,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;sBA85BL,IAAI,CAAC,IAAI,CAAC,UAAU,KAAK,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,QAAQ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;QA2kBvE,CAAC;AACT,CAAC"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/chat.ts"],"names":[],"mappings":"AAwDA,UAAU,WAAW;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAkLD,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,
|
|
1
|
+
{"version":3,"file":"chat.d.ts","sourceRoot":"","sources":["../../../src/cli/commands/chat.ts"],"names":[],"mappings":"AAwDA,UAAU,WAAW;IACnB,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,UAAU,CAAC,EAAE,OAAO,CAAC;IACrB,iBAAiB,CAAC,EAAE,OAAO,CAAC;IAC5B,gBAAgB,CAAC,EAAE,OAAO,CAAC;CAC5B;AAkLD,wBAAsB,WAAW,CAAC,OAAO,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CAq7DrE"}
|