claude-cortex 1.0.0 → 1.1.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.
- package/dashboard/README.md +36 -0
- package/dashboard/components.json +22 -0
- package/dashboard/eslint.config.mjs +18 -0
- package/dashboard/next.config.ts +7 -0
- package/dashboard/package-lock.json +7784 -0
- package/dashboard/package.json +42 -0
- package/dashboard/postcss.config.mjs +7 -0
- package/dashboard/public/file.svg +1 -0
- package/dashboard/public/globe.svg +1 -0
- package/dashboard/public/next.svg +1 -0
- package/dashboard/public/vercel.svg +1 -0
- package/dashboard/public/window.svg +1 -0
- package/dashboard/src/app/favicon.ico +0 -0
- package/dashboard/src/app/globals.css +125 -0
- package/dashboard/src/app/layout.tsx +35 -0
- package/dashboard/src/app/page.tsx +338 -0
- package/dashboard/src/components/Providers.tsx +27 -0
- package/dashboard/src/components/brain/ActivityPulseSystem.tsx +229 -0
- package/dashboard/src/components/brain/BrainMesh.tsx +118 -0
- package/dashboard/src/components/brain/BrainRegions.tsx +254 -0
- package/dashboard/src/components/brain/BrainScene.tsx +255 -0
- package/dashboard/src/components/brain/CategoryLabels.tsx +103 -0
- package/dashboard/src/components/brain/CoreSphere.tsx +215 -0
- package/dashboard/src/components/brain/DataFlowParticles.tsx +123 -0
- package/dashboard/src/components/brain/DataStreamRings.tsx +161 -0
- package/dashboard/src/components/brain/ElectronFlow.tsx +323 -0
- package/dashboard/src/components/brain/HolographicGrid.tsx +235 -0
- package/dashboard/src/components/brain/MemoryLinks.tsx +271 -0
- package/dashboard/src/components/brain/MemoryNode.tsx +245 -0
- package/dashboard/src/components/brain/NeuralPathways.tsx +441 -0
- package/dashboard/src/components/brain/SynapseNodes.tsx +306 -0
- package/dashboard/src/components/brain/TimelineControls.tsx +205 -0
- package/dashboard/src/components/chip/ChipScene.tsx +497 -0
- package/dashboard/src/components/chip/ChipSubstrate.tsx +238 -0
- package/dashboard/src/components/chip/CortexCore.tsx +210 -0
- package/dashboard/src/components/chip/DataBus.tsx +416 -0
- package/dashboard/src/components/chip/MemoryCell.tsx +225 -0
- package/dashboard/src/components/chip/MemoryGrid.tsx +328 -0
- package/dashboard/src/components/chip/QuantumCell.tsx +316 -0
- package/dashboard/src/components/chip/SectionLabel.tsx +113 -0
- package/dashboard/src/components/chip/index.ts +14 -0
- package/dashboard/src/components/controls/ControlPanel.tsx +100 -0
- package/dashboard/src/components/dashboard/StatsPanel.tsx +164 -0
- package/dashboard/src/components/debug/ActivityLog.tsx +238 -0
- package/dashboard/src/components/debug/DebugPanel.tsx +101 -0
- package/dashboard/src/components/debug/QueryTester.tsx +192 -0
- package/dashboard/src/components/debug/RelationshipGraph.tsx +403 -0
- package/dashboard/src/components/debug/SqlConsole.tsx +313 -0
- package/dashboard/src/components/memory/MemoryDetail.tsx +325 -0
- package/dashboard/src/components/ui/button.tsx +62 -0
- package/dashboard/src/components/ui/card.tsx +92 -0
- package/dashboard/src/components/ui/input.tsx +21 -0
- package/dashboard/src/hooks/useDebouncedValue.ts +24 -0
- package/dashboard/src/hooks/useMemories.ts +276 -0
- package/dashboard/src/hooks/useSuggestions.ts +46 -0
- package/dashboard/src/lib/category-colors.ts +84 -0
- package/dashboard/src/lib/position-algorithm.ts +177 -0
- package/dashboard/src/lib/simplex-noise.ts +217 -0
- package/dashboard/src/lib/store.ts +88 -0
- package/dashboard/src/lib/utils.ts +6 -0
- package/dashboard/src/lib/websocket.ts +216 -0
- package/dashboard/src/types/memory.ts +73 -0
- package/dashboard/tsconfig.json +34 -0
- package/dist/api/control.d.ts +27 -0
- package/dist/api/control.d.ts.map +1 -0
- package/dist/api/control.js +60 -0
- package/dist/api/control.js.map +1 -0
- package/dist/api/visualization-server.d.ts.map +1 -1
- package/dist/api/visualization-server.js +109 -2
- package/dist/api/visualization-server.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +80 -4
- package/dist/index.js.map +1 -1
- package/dist/memory/store.d.ts +6 -0
- package/dist/memory/store.d.ts.map +1 -1
- package/dist/memory/store.js +14 -0
- package/dist/memory/store.js.map +1 -1
- package/package.json +7 -3
|
@@ -0,0 +1,229 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Activity Pulse System
|
|
5
|
+
*
|
|
6
|
+
* Creates visual pulses when memory events occur:
|
|
7
|
+
* - memory_created: Green expanding pulse at memory position
|
|
8
|
+
* - memory_accessed: Blue flash at memory position
|
|
9
|
+
* - link_discovered: Cyan line connecting two memories
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { useRef, useMemo } from 'react';
|
|
13
|
+
import { useFrame } from '@react-three/fiber';
|
|
14
|
+
import * as THREE from 'three';
|
|
15
|
+
|
|
16
|
+
interface Pulse {
|
|
17
|
+
id: number;
|
|
18
|
+
type: 'created' | 'accessed' | 'linked';
|
|
19
|
+
position: [number, number, number];
|
|
20
|
+
targetPosition?: [number, number, number]; // For links
|
|
21
|
+
startTime: number;
|
|
22
|
+
duration: number;
|
|
23
|
+
color: string;
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
interface ActivityPulseSystemProps {
|
|
27
|
+
pulses: Pulse[];
|
|
28
|
+
onPulseComplete: (id: number) => void;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
// Shared geometry
|
|
32
|
+
const PULSE_GEOMETRY = new THREE.RingGeometry(0.1, 0.15, 32);
|
|
33
|
+
const SPHERE_GEOMETRY = new THREE.SphereGeometry(0.1, 16, 16);
|
|
34
|
+
|
|
35
|
+
function CreatedPulse({
|
|
36
|
+
pulse,
|
|
37
|
+
onComplete,
|
|
38
|
+
}: {
|
|
39
|
+
pulse: Pulse;
|
|
40
|
+
onComplete: () => void;
|
|
41
|
+
}) {
|
|
42
|
+
const meshRef = useRef<THREE.Mesh>(null);
|
|
43
|
+
const startTimeRef = useRef<number | null>(null);
|
|
44
|
+
|
|
45
|
+
useFrame((state) => {
|
|
46
|
+
if (!meshRef.current) return;
|
|
47
|
+
|
|
48
|
+
// Initialize start time on first frame
|
|
49
|
+
if (startTimeRef.current === null) {
|
|
50
|
+
startTimeRef.current = state.clock.elapsedTime;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
const elapsed = state.clock.elapsedTime - startTimeRef.current;
|
|
54
|
+
const progress = elapsed / (pulse.duration / 1000); // Convert ms to seconds
|
|
55
|
+
|
|
56
|
+
if (progress >= 1) {
|
|
57
|
+
onComplete();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// Expanding ring that fades out
|
|
62
|
+
const scale = 0.5 + progress * 3;
|
|
63
|
+
const opacity = (1 - progress) * 0.8;
|
|
64
|
+
|
|
65
|
+
meshRef.current.scale.setScalar(scale);
|
|
66
|
+
(meshRef.current.material as THREE.MeshBasicMaterial).opacity = opacity;
|
|
67
|
+
});
|
|
68
|
+
|
|
69
|
+
return (
|
|
70
|
+
<mesh
|
|
71
|
+
ref={meshRef}
|
|
72
|
+
position={pulse.position}
|
|
73
|
+
rotation={[Math.PI / 2, 0, 0]}
|
|
74
|
+
geometry={PULSE_GEOMETRY}
|
|
75
|
+
>
|
|
76
|
+
<meshBasicMaterial
|
|
77
|
+
color={pulse.color}
|
|
78
|
+
transparent
|
|
79
|
+
opacity={0.8}
|
|
80
|
+
side={THREE.DoubleSide}
|
|
81
|
+
depthWrite={false}
|
|
82
|
+
/>
|
|
83
|
+
</mesh>
|
|
84
|
+
);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
function AccessedPulse({
|
|
88
|
+
pulse,
|
|
89
|
+
onComplete,
|
|
90
|
+
}: {
|
|
91
|
+
pulse: Pulse;
|
|
92
|
+
onComplete: () => void;
|
|
93
|
+
}) {
|
|
94
|
+
const meshRef = useRef<THREE.Mesh>(null);
|
|
95
|
+
const startTimeRef = useRef<number | null>(null);
|
|
96
|
+
|
|
97
|
+
useFrame((state) => {
|
|
98
|
+
if (!meshRef.current) return;
|
|
99
|
+
|
|
100
|
+
// Initialize start time on first frame
|
|
101
|
+
if (startTimeRef.current === null) {
|
|
102
|
+
startTimeRef.current = state.clock.elapsedTime;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const elapsed = state.clock.elapsedTime - startTimeRef.current;
|
|
106
|
+
const progress = elapsed / (pulse.duration / 1000); // Convert ms to seconds
|
|
107
|
+
|
|
108
|
+
if (progress >= 1) {
|
|
109
|
+
onComplete();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
// Flash that expands slightly then fades
|
|
114
|
+
const flash = Math.sin(progress * Math.PI);
|
|
115
|
+
const scale = 0.8 + flash * 0.6;
|
|
116
|
+
const opacity = flash * 0.9;
|
|
117
|
+
|
|
118
|
+
meshRef.current.scale.setScalar(scale);
|
|
119
|
+
(meshRef.current.material as THREE.MeshBasicMaterial).opacity = opacity;
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
return (
|
|
123
|
+
<mesh ref={meshRef} position={pulse.position} geometry={SPHERE_GEOMETRY}>
|
|
124
|
+
<meshBasicMaterial
|
|
125
|
+
color={pulse.color}
|
|
126
|
+
transparent
|
|
127
|
+
opacity={0.9}
|
|
128
|
+
depthWrite={false}
|
|
129
|
+
/>
|
|
130
|
+
</mesh>
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
|
|
134
|
+
function LinkedPulse({
|
|
135
|
+
pulse,
|
|
136
|
+
onComplete,
|
|
137
|
+
}: {
|
|
138
|
+
pulse: Pulse;
|
|
139
|
+
onComplete: () => void;
|
|
140
|
+
}) {
|
|
141
|
+
const groupRef = useRef<THREE.Group>(null);
|
|
142
|
+
const startTimeRef = useRef<number | null>(null);
|
|
143
|
+
const lineRef = useRef<THREE.Line | null>(null);
|
|
144
|
+
|
|
145
|
+
// Create line object once
|
|
146
|
+
const lineObject = useMemo(() => {
|
|
147
|
+
const points = [
|
|
148
|
+
new THREE.Vector3(...pulse.position),
|
|
149
|
+
new THREE.Vector3(...(pulse.targetPosition || pulse.position)),
|
|
150
|
+
];
|
|
151
|
+
const geometry = new THREE.BufferGeometry().setFromPoints(points);
|
|
152
|
+
const material = new THREE.LineBasicMaterial({
|
|
153
|
+
color: pulse.color,
|
|
154
|
+
transparent: true,
|
|
155
|
+
opacity: 0.8,
|
|
156
|
+
});
|
|
157
|
+
return new THREE.Line(geometry, material);
|
|
158
|
+
}, [pulse.position, pulse.targetPosition, pulse.color]);
|
|
159
|
+
|
|
160
|
+
useFrame((state) => {
|
|
161
|
+
if (!lineRef.current) {
|
|
162
|
+
// Add line to group on first render
|
|
163
|
+
if (groupRef.current && !groupRef.current.children.length) {
|
|
164
|
+
groupRef.current.add(lineObject);
|
|
165
|
+
lineRef.current = lineObject;
|
|
166
|
+
}
|
|
167
|
+
return;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Initialize start time on first frame
|
|
171
|
+
if (startTimeRef.current === null) {
|
|
172
|
+
startTimeRef.current = state.clock.elapsedTime;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
const elapsed = state.clock.elapsedTime - startTimeRef.current;
|
|
176
|
+
const progress = elapsed / (pulse.duration / 1000); // Convert ms to seconds
|
|
177
|
+
|
|
178
|
+
if (progress >= 1) {
|
|
179
|
+
onComplete();
|
|
180
|
+
return;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// Line that appears then fades
|
|
184
|
+
const flash = Math.sin(progress * Math.PI);
|
|
185
|
+
(lineRef.current.material as THREE.LineBasicMaterial).opacity = flash * 0.8;
|
|
186
|
+
});
|
|
187
|
+
|
|
188
|
+
return <group ref={groupRef} />;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
export function ActivityPulseSystem({ pulses, onPulseComplete }: ActivityPulseSystemProps) {
|
|
192
|
+
return (
|
|
193
|
+
<group name="activity-pulses">
|
|
194
|
+
{pulses.map((pulse) => {
|
|
195
|
+
switch (pulse.type) {
|
|
196
|
+
case 'created':
|
|
197
|
+
return (
|
|
198
|
+
<CreatedPulse
|
|
199
|
+
key={pulse.id}
|
|
200
|
+
pulse={pulse}
|
|
201
|
+
onComplete={() => onPulseComplete(pulse.id)}
|
|
202
|
+
/>
|
|
203
|
+
);
|
|
204
|
+
case 'accessed':
|
|
205
|
+
return (
|
|
206
|
+
<AccessedPulse
|
|
207
|
+
key={pulse.id}
|
|
208
|
+
pulse={pulse}
|
|
209
|
+
onComplete={() => onPulseComplete(pulse.id)}
|
|
210
|
+
/>
|
|
211
|
+
);
|
|
212
|
+
case 'linked':
|
|
213
|
+
return (
|
|
214
|
+
<LinkedPulse
|
|
215
|
+
key={pulse.id}
|
|
216
|
+
pulse={pulse}
|
|
217
|
+
onComplete={() => onPulseComplete(pulse.id)}
|
|
218
|
+
/>
|
|
219
|
+
);
|
|
220
|
+
default:
|
|
221
|
+
return null;
|
|
222
|
+
}
|
|
223
|
+
})}
|
|
224
|
+
</group>
|
|
225
|
+
);
|
|
226
|
+
}
|
|
227
|
+
|
|
228
|
+
// Type export for use in parent components
|
|
229
|
+
export type { Pulse };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Brain Mesh
|
|
5
|
+
* Ghost wireframe outline of a brain shape for subtle context
|
|
6
|
+
* Uses simplex noise to create organic cortex-like surface folds
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { useMemo, useEffect } from 'react';
|
|
10
|
+
import * as THREE from 'three';
|
|
11
|
+
import { fbm3D, ridged3D } from '@/lib/simplex-noise';
|
|
12
|
+
|
|
13
|
+
interface BrainMeshProps {
|
|
14
|
+
opacity?: number;
|
|
15
|
+
showWireframe?: boolean;
|
|
16
|
+
pulseIntensity?: number;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* Creates a brain-like geometry with cortex folds
|
|
21
|
+
*/
|
|
22
|
+
function createBrainGeometry(): THREE.BufferGeometry {
|
|
23
|
+
// Start with icosahedron for smooth organic base
|
|
24
|
+
const geo = new THREE.IcosahedronGeometry(3.5, 5);
|
|
25
|
+
const positions = geo.attributes.position.array as Float32Array;
|
|
26
|
+
const colors = new Float32Array(positions.length);
|
|
27
|
+
|
|
28
|
+
for (let i = 0; i < positions.length; i += 3) {
|
|
29
|
+
let x = positions[i];
|
|
30
|
+
let y = positions[i + 1];
|
|
31
|
+
let z = positions[i + 2];
|
|
32
|
+
|
|
33
|
+
// Normalize to get direction
|
|
34
|
+
const length = Math.sqrt(x * x + y * y + z * z);
|
|
35
|
+
const nx = x / length;
|
|
36
|
+
const ny = y / length;
|
|
37
|
+
const nz = z / length;
|
|
38
|
+
|
|
39
|
+
// Multi-scale noise for cortex folds
|
|
40
|
+
// Large folds (gyri)
|
|
41
|
+
const largeNoise = fbm3D(nx * 2, ny * 2, nz * 2, 3, 2, 0.5) * 0.4;
|
|
42
|
+
// Medium detail
|
|
43
|
+
const mediumNoise = fbm3D(nx * 4, ny * 4, nz * 4, 2, 2, 0.5) * 0.15;
|
|
44
|
+
// Fine sulci (ridged for sharp creases)
|
|
45
|
+
const fineNoise = ridged3D(nx * 6, ny * 6, nz * 6, 2, 2, 0.5) * 0.08;
|
|
46
|
+
|
|
47
|
+
const totalNoise = largeNoise + mediumNoise + fineNoise * 0.5;
|
|
48
|
+
|
|
49
|
+
// Brain shape modifications:
|
|
50
|
+
// 1. Elongate front-to-back (Z axis) - frontal lobe
|
|
51
|
+
// 2. Slightly flatten top-bottom (Y axis)
|
|
52
|
+
// 3. Hemisphere bulges on sides (X axis)
|
|
53
|
+
const shapeX = 1.2 + Math.abs(nz) * 0.15; // Wider at sides
|
|
54
|
+
const shapeY = 0.85 + Math.abs(nx) * 0.1; // Slightly flat
|
|
55
|
+
const shapeZ = 1.1 - Math.abs(ny) * 0.1; // Elongated front-back
|
|
56
|
+
|
|
57
|
+
// Central fissure (divide hemispheres)
|
|
58
|
+
const centralFissure = Math.abs(nx) < 0.1 ? -0.15 * (1 - Math.abs(nx) / 0.1) : 0;
|
|
59
|
+
|
|
60
|
+
// Temporal lobe bulge
|
|
61
|
+
const temporalBulge = (Math.abs(nx) > 0.5 && nz < 0) ? 0.15 : 0;
|
|
62
|
+
|
|
63
|
+
// Apply all modifications
|
|
64
|
+
const radius = length * (1 + totalNoise + centralFissure + temporalBulge);
|
|
65
|
+
|
|
66
|
+
positions[i] = nx * radius * shapeX;
|
|
67
|
+
positions[i + 1] = ny * radius * shapeY;
|
|
68
|
+
positions[i + 2] = nz * radius * shapeZ;
|
|
69
|
+
|
|
70
|
+
// Color based on region (for visual depth)
|
|
71
|
+
// Front (STM) = orange tint, Middle (Episodic) = purple, Back (LTM) = blue
|
|
72
|
+
const normalizedZ = (nz + 1) / 2; // 0 to 1
|
|
73
|
+
colors[i] = 0.1 + normalizedZ * 0.2; // R: more red in front
|
|
74
|
+
colors[i + 1] = 0.05 + (1 - normalizedZ) * 0.15; // G: more green in back
|
|
75
|
+
colors[i + 2] = 0.2 + (1 - normalizedZ) * 0.3; // B: more blue in back
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
geo.computeVertexNormals();
|
|
79
|
+
geo.setAttribute('color', new THREE.BufferAttribute(colors, 3));
|
|
80
|
+
|
|
81
|
+
return geo;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
export function BrainMesh({
|
|
85
|
+
opacity = 0.05,
|
|
86
|
+
showWireframe = true,
|
|
87
|
+
}: BrainMeshProps) {
|
|
88
|
+
// Create geometry once
|
|
89
|
+
const brainGeometry = useMemo(() => createBrainGeometry(), []);
|
|
90
|
+
|
|
91
|
+
// Ghost wireframe material - very faint gray
|
|
92
|
+
const wireframeMaterial = useMemo(
|
|
93
|
+
() =>
|
|
94
|
+
new THREE.MeshBasicMaterial({
|
|
95
|
+
color: '#333333',
|
|
96
|
+
wireframe: true,
|
|
97
|
+
transparent: true,
|
|
98
|
+
opacity: opacity,
|
|
99
|
+
}),
|
|
100
|
+
[opacity]
|
|
101
|
+
);
|
|
102
|
+
|
|
103
|
+
// Cleanup on unmount to prevent GPU memory leaks
|
|
104
|
+
useEffect(() => {
|
|
105
|
+
return () => {
|
|
106
|
+
brainGeometry.dispose();
|
|
107
|
+
wireframeMaterial.dispose();
|
|
108
|
+
};
|
|
109
|
+
}, [brainGeometry, wireframeMaterial]);
|
|
110
|
+
|
|
111
|
+
// Only render wireframe - no solid surface, no core, no animation
|
|
112
|
+
if (!showWireframe) return null;
|
|
113
|
+
|
|
114
|
+
return (
|
|
115
|
+
<mesh geometry={brainGeometry} material={wireframeMaterial} />
|
|
116
|
+
);
|
|
117
|
+
}
|
|
118
|
+
|
|
@@ -0,0 +1,254 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Brain Regions
|
|
5
|
+
* Volumetric cloud-like regions representing different memory types
|
|
6
|
+
* - Short-term (front/orange): Active working memory
|
|
7
|
+
* - Episodic (middle/purple): Session and event memories
|
|
8
|
+
* - Long-term (back/blue): Consolidated stable memories
|
|
9
|
+
*/
|
|
10
|
+
|
|
11
|
+
import { useRef, useMemo } from 'react';
|
|
12
|
+
import { useFrame } from '@react-three/fiber';
|
|
13
|
+
import { Html } from '@react-three/drei';
|
|
14
|
+
import * as THREE from 'three';
|
|
15
|
+
|
|
16
|
+
interface MemoryRegionProps {
|
|
17
|
+
type: 'short_term' | 'episodic' | 'long_term';
|
|
18
|
+
position: [number, number, number];
|
|
19
|
+
color: string;
|
|
20
|
+
memoryCount?: number;
|
|
21
|
+
label: string;
|
|
22
|
+
showLabel?: boolean;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Single volumetric memory region
|
|
27
|
+
* Uses multiple overlapping transparent spheres for cloud effect
|
|
28
|
+
*/
|
|
29
|
+
function MemoryRegion({
|
|
30
|
+
type,
|
|
31
|
+
position,
|
|
32
|
+
color,
|
|
33
|
+
memoryCount = 0,
|
|
34
|
+
label,
|
|
35
|
+
showLabel = true,
|
|
36
|
+
}: MemoryRegionProps) {
|
|
37
|
+
const groupRef = useRef<THREE.Group>(null);
|
|
38
|
+
const innerRef = useRef<THREE.Mesh>(null);
|
|
39
|
+
|
|
40
|
+
// Scale based on memory count (more memories = larger region)
|
|
41
|
+
const scale = useMemo(() => {
|
|
42
|
+
const baseScale = 1;
|
|
43
|
+
const countScale = Math.min(memoryCount / 30, 0.5); // Max 50% increase
|
|
44
|
+
return baseScale + countScale;
|
|
45
|
+
}, [memoryCount]);
|
|
46
|
+
|
|
47
|
+
// Create multiple sphere layers for volumetric effect
|
|
48
|
+
const layers = useMemo(() => {
|
|
49
|
+
return [
|
|
50
|
+
{ radius: 1.8, opacity: 0.03, offset: [0, 0, 0] },
|
|
51
|
+
{ radius: 1.5, opacity: 0.04, offset: [0.2, 0.1, 0.1] },
|
|
52
|
+
{ radius: 1.2, opacity: 0.05, offset: [-0.1, 0.15, -0.1] },
|
|
53
|
+
{ radius: 0.9, opacity: 0.06, offset: [0.1, -0.1, 0.15] },
|
|
54
|
+
{ radius: 0.6, opacity: 0.08, offset: [0, 0.05, 0] },
|
|
55
|
+
];
|
|
56
|
+
}, []);
|
|
57
|
+
|
|
58
|
+
// Animation
|
|
59
|
+
useFrame((state) => {
|
|
60
|
+
if (!groupRef.current) return;
|
|
61
|
+
|
|
62
|
+
const time = state.clock.elapsedTime;
|
|
63
|
+
const typeOffset = type === 'short_term' ? 0 : type === 'episodic' ? 1 : 2;
|
|
64
|
+
|
|
65
|
+
// Gentle floating motion
|
|
66
|
+
groupRef.current.position.y =
|
|
67
|
+
position[1] + Math.sin(time * 0.3 + typeOffset) * 0.15;
|
|
68
|
+
|
|
69
|
+
// Subtle rotation
|
|
70
|
+
groupRef.current.rotation.y = Math.sin(time * 0.2 + typeOffset) * 0.1;
|
|
71
|
+
|
|
72
|
+
// Inner core pulsing
|
|
73
|
+
if (innerRef.current) {
|
|
74
|
+
const pulse = Math.sin(time * 1.5 + typeOffset * 2) * 0.15 + 0.85;
|
|
75
|
+
innerRef.current.scale.setScalar(pulse);
|
|
76
|
+
(innerRef.current.material as THREE.MeshBasicMaterial).opacity =
|
|
77
|
+
0.15 + pulse * 0.1;
|
|
78
|
+
}
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
return (
|
|
82
|
+
<group ref={groupRef} position={position}>
|
|
83
|
+
{/* Volumetric cloud layers */}
|
|
84
|
+
{layers.map((layer, i) => (
|
|
85
|
+
<mesh
|
|
86
|
+
key={i}
|
|
87
|
+
position={[
|
|
88
|
+
layer.offset[0] * scale,
|
|
89
|
+
layer.offset[1] * scale,
|
|
90
|
+
layer.offset[2] * scale,
|
|
91
|
+
]}
|
|
92
|
+
scale={scale}
|
|
93
|
+
>
|
|
94
|
+
<sphereGeometry args={[layer.radius, 24, 24]} />
|
|
95
|
+
<meshStandardMaterial
|
|
96
|
+
color={color}
|
|
97
|
+
transparent
|
|
98
|
+
opacity={layer.opacity}
|
|
99
|
+
emissive={color}
|
|
100
|
+
emissiveIntensity={0.15}
|
|
101
|
+
side={THREE.DoubleSide}
|
|
102
|
+
depthWrite={false}
|
|
103
|
+
/>
|
|
104
|
+
</mesh>
|
|
105
|
+
))}
|
|
106
|
+
|
|
107
|
+
{/* Bright inner core */}
|
|
108
|
+
<mesh ref={innerRef} scale={scale * 0.4}>
|
|
109
|
+
<sphereGeometry args={[1, 16, 16]} />
|
|
110
|
+
<meshBasicMaterial
|
|
111
|
+
color={color}
|
|
112
|
+
transparent
|
|
113
|
+
opacity={0.2}
|
|
114
|
+
depthWrite={false}
|
|
115
|
+
/>
|
|
116
|
+
</mesh>
|
|
117
|
+
|
|
118
|
+
{/* Region label */}
|
|
119
|
+
{showLabel && (
|
|
120
|
+
<Html position={[0, 2.2 * scale, 0]} center style={{ pointerEvents: 'none' }}>
|
|
121
|
+
<div
|
|
122
|
+
className="px-3 py-1.5 rounded-full text-xs font-bold whitespace-nowrap backdrop-blur-sm"
|
|
123
|
+
style={{
|
|
124
|
+
backgroundColor: `${color}25`,
|
|
125
|
+
color: color,
|
|
126
|
+
border: `1px solid ${color}40`,
|
|
127
|
+
boxShadow: `0 0 20px ${color}30`,
|
|
128
|
+
}}
|
|
129
|
+
>
|
|
130
|
+
{label}
|
|
131
|
+
{memoryCount > 0 && (
|
|
132
|
+
<span className="ml-2 opacity-70">({memoryCount})</span>
|
|
133
|
+
)}
|
|
134
|
+
</div>
|
|
135
|
+
</Html>
|
|
136
|
+
)}
|
|
137
|
+
</group>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/**
|
|
142
|
+
* Energy field connecting regions
|
|
143
|
+
*/
|
|
144
|
+
function EnergyField() {
|
|
145
|
+
const meshRef = useRef<THREE.Mesh>(null);
|
|
146
|
+
|
|
147
|
+
useFrame((state) => {
|
|
148
|
+
if (!meshRef.current) return;
|
|
149
|
+
const time = state.clock.elapsedTime;
|
|
150
|
+
|
|
151
|
+
// Slow rotation
|
|
152
|
+
meshRef.current.rotation.y = time * 0.05;
|
|
153
|
+
meshRef.current.rotation.x = Math.sin(time * 0.1) * 0.1;
|
|
154
|
+
|
|
155
|
+
// Pulsing opacity
|
|
156
|
+
(meshRef.current.material as THREE.MeshBasicMaterial).opacity =
|
|
157
|
+
0.02 + Math.sin(time * 0.5) * 0.01;
|
|
158
|
+
});
|
|
159
|
+
|
|
160
|
+
return (
|
|
161
|
+
<mesh ref={meshRef}>
|
|
162
|
+
<torusGeometry args={[3.5, 0.8, 8, 48]} />
|
|
163
|
+
<meshBasicMaterial
|
|
164
|
+
color="#6366f1"
|
|
165
|
+
transparent
|
|
166
|
+
opacity={0.025}
|
|
167
|
+
side={THREE.DoubleSide}
|
|
168
|
+
depthWrite={false}
|
|
169
|
+
/>
|
|
170
|
+
</mesh>
|
|
171
|
+
);
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Orbital ring around the brain
|
|
176
|
+
*/
|
|
177
|
+
function OrbitalRing({ radius = 4.5, color = '#4488ff' }: { radius?: number; color?: string }) {
|
|
178
|
+
const ringRef = useRef<THREE.Mesh>(null);
|
|
179
|
+
|
|
180
|
+
useFrame((state) => {
|
|
181
|
+
if (!ringRef.current) return;
|
|
182
|
+
ringRef.current.rotation.z = state.clock.elapsedTime * 0.1;
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
return (
|
|
186
|
+
<mesh ref={ringRef} rotation={[Math.PI / 2, 0, 0]}>
|
|
187
|
+
<torusGeometry args={[radius, 0.015, 8, 64]} />
|
|
188
|
+
<meshBasicMaterial color={color} transparent opacity={0.3} />
|
|
189
|
+
</mesh>
|
|
190
|
+
);
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
interface BrainRegionsProps {
|
|
194
|
+
shortTermCount?: number;
|
|
195
|
+
episodicCount?: number;
|
|
196
|
+
longTermCount?: number;
|
|
197
|
+
showLabels?: boolean;
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* All brain regions combined
|
|
202
|
+
*/
|
|
203
|
+
export function BrainRegions({
|
|
204
|
+
shortTermCount = 0,
|
|
205
|
+
episodicCount = 0,
|
|
206
|
+
longTermCount = 0,
|
|
207
|
+
showLabels = false,
|
|
208
|
+
}: BrainRegionsProps) {
|
|
209
|
+
return (
|
|
210
|
+
<group name="brain-regions">
|
|
211
|
+
{/* Short-term memory region (front) */}
|
|
212
|
+
<MemoryRegion
|
|
213
|
+
type="short_term"
|
|
214
|
+
position={[0, 0, 2.8]}
|
|
215
|
+
color="#F97316"
|
|
216
|
+
memoryCount={shortTermCount}
|
|
217
|
+
label="Short-Term"
|
|
218
|
+
showLabel={showLabels}
|
|
219
|
+
/>
|
|
220
|
+
|
|
221
|
+
{/* Episodic memory region (middle) */}
|
|
222
|
+
<MemoryRegion
|
|
223
|
+
type="episodic"
|
|
224
|
+
position={[0, 0.3, 0]}
|
|
225
|
+
color="#8B5CF6"
|
|
226
|
+
memoryCount={episodicCount}
|
|
227
|
+
label="Episodic"
|
|
228
|
+
showLabel={showLabels}
|
|
229
|
+
/>
|
|
230
|
+
|
|
231
|
+
{/* Long-term memory region (back) */}
|
|
232
|
+
<MemoryRegion
|
|
233
|
+
type="long_term"
|
|
234
|
+
position={[0, 0, -2.8]}
|
|
235
|
+
color="#3B82F6"
|
|
236
|
+
memoryCount={longTermCount}
|
|
237
|
+
label="Long-Term"
|
|
238
|
+
showLabel={showLabels}
|
|
239
|
+
/>
|
|
240
|
+
|
|
241
|
+
{/* Energy field connecting regions */}
|
|
242
|
+
<EnergyField />
|
|
243
|
+
|
|
244
|
+
{/* Orbital rings for sci-fi effect */}
|
|
245
|
+
<OrbitalRing radius={4.2} color="#3B82F6" />
|
|
246
|
+
<group rotation={[0, 0, Math.PI / 6]}>
|
|
247
|
+
<OrbitalRing radius={4.5} color="#8B5CF6" />
|
|
248
|
+
</group>
|
|
249
|
+
<group rotation={[0, 0, -Math.PI / 6]}>
|
|
250
|
+
<OrbitalRing radius={4.8} color="#F97316" />
|
|
251
|
+
</group>
|
|
252
|
+
</group>
|
|
253
|
+
);
|
|
254
|
+
}
|