claude-cortex 1.0.0 → 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.
Files changed (79) hide show
  1. package/dashboard/README.md +36 -0
  2. package/dashboard/components.json +22 -0
  3. package/dashboard/eslint.config.mjs +18 -0
  4. package/dashboard/next.config.ts +7 -0
  5. package/dashboard/package-lock.json +7784 -0
  6. package/dashboard/package.json +42 -0
  7. package/dashboard/postcss.config.mjs +7 -0
  8. package/dashboard/public/file.svg +1 -0
  9. package/dashboard/public/globe.svg +1 -0
  10. package/dashboard/public/next.svg +1 -0
  11. package/dashboard/public/vercel.svg +1 -0
  12. package/dashboard/public/window.svg +1 -0
  13. package/dashboard/src/app/favicon.ico +0 -0
  14. package/dashboard/src/app/globals.css +125 -0
  15. package/dashboard/src/app/layout.tsx +35 -0
  16. package/dashboard/src/app/page.tsx +338 -0
  17. package/dashboard/src/components/Providers.tsx +27 -0
  18. package/dashboard/src/components/brain/ActivityPulseSystem.tsx +229 -0
  19. package/dashboard/src/components/brain/BrainMesh.tsx +118 -0
  20. package/dashboard/src/components/brain/BrainRegions.tsx +254 -0
  21. package/dashboard/src/components/brain/BrainScene.tsx +255 -0
  22. package/dashboard/src/components/brain/CategoryLabels.tsx +103 -0
  23. package/dashboard/src/components/brain/CoreSphere.tsx +215 -0
  24. package/dashboard/src/components/brain/DataFlowParticles.tsx +123 -0
  25. package/dashboard/src/components/brain/DataStreamRings.tsx +161 -0
  26. package/dashboard/src/components/brain/ElectronFlow.tsx +323 -0
  27. package/dashboard/src/components/brain/HolographicGrid.tsx +235 -0
  28. package/dashboard/src/components/brain/MemoryLinks.tsx +271 -0
  29. package/dashboard/src/components/brain/MemoryNode.tsx +245 -0
  30. package/dashboard/src/components/brain/NeuralPathways.tsx +441 -0
  31. package/dashboard/src/components/brain/SynapseNodes.tsx +306 -0
  32. package/dashboard/src/components/brain/TimelineControls.tsx +205 -0
  33. package/dashboard/src/components/chip/ChipScene.tsx +497 -0
  34. package/dashboard/src/components/chip/ChipSubstrate.tsx +238 -0
  35. package/dashboard/src/components/chip/CortexCore.tsx +210 -0
  36. package/dashboard/src/components/chip/DataBus.tsx +416 -0
  37. package/dashboard/src/components/chip/MemoryCell.tsx +225 -0
  38. package/dashboard/src/components/chip/MemoryGrid.tsx +328 -0
  39. package/dashboard/src/components/chip/QuantumCell.tsx +316 -0
  40. package/dashboard/src/components/chip/SectionLabel.tsx +113 -0
  41. package/dashboard/src/components/chip/index.ts +14 -0
  42. package/dashboard/src/components/controls/ControlPanel.tsx +100 -0
  43. package/dashboard/src/components/dashboard/StatsPanel.tsx +164 -0
  44. package/dashboard/src/components/debug/ActivityLog.tsx +238 -0
  45. package/dashboard/src/components/debug/DebugPanel.tsx +101 -0
  46. package/dashboard/src/components/debug/QueryTester.tsx +192 -0
  47. package/dashboard/src/components/debug/RelationshipGraph.tsx +403 -0
  48. package/dashboard/src/components/debug/SqlConsole.tsx +313 -0
  49. package/dashboard/src/components/memory/MemoryDetail.tsx +325 -0
  50. package/dashboard/src/components/ui/button.tsx +62 -0
  51. package/dashboard/src/components/ui/card.tsx +92 -0
  52. package/dashboard/src/components/ui/input.tsx +21 -0
  53. package/dashboard/src/hooks/useDebouncedValue.ts +24 -0
  54. package/dashboard/src/hooks/useMemories.ts +276 -0
  55. package/dashboard/src/hooks/useSuggestions.ts +46 -0
  56. package/dashboard/src/lib/category-colors.ts +84 -0
  57. package/dashboard/src/lib/position-algorithm.ts +177 -0
  58. package/dashboard/src/lib/simplex-noise.ts +217 -0
  59. package/dashboard/src/lib/store.ts +88 -0
  60. package/dashboard/src/lib/utils.ts +6 -0
  61. package/dashboard/src/lib/websocket.ts +216 -0
  62. package/dashboard/src/types/memory.ts +73 -0
  63. package/dashboard/tsconfig.json +34 -0
  64. package/dist/api/control.d.ts +27 -0
  65. package/dist/api/control.d.ts.map +1 -0
  66. package/dist/api/control.js +60 -0
  67. package/dist/api/control.js.map +1 -0
  68. package/dist/api/visualization-server.d.ts.map +1 -1
  69. package/dist/api/visualization-server.js +109 -2
  70. package/dist/api/visualization-server.js.map +1 -1
  71. package/dist/index.d.ts +2 -1
  72. package/dist/index.d.ts.map +1 -1
  73. package/dist/index.js +80 -4
  74. package/dist/index.js.map +1 -1
  75. package/dist/memory/store.d.ts +6 -0
  76. package/dist/memory/store.d.ts.map +1 -1
  77. package/dist/memory/store.js +14 -0
  78. package/dist/memory/store.js.map +1 -1
  79. package/package.json +7 -3
@@ -0,0 +1,328 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * Memory Grid
5
+ * Organizes memories in a grid layout within each memory bank section
6
+ * Automatically switches between MemoryCell and QuantumCell based on salience
7
+ */
8
+
9
+ import { useMemo } from 'react';
10
+ import { Memory, MemoryType } from '@/types/memory';
11
+ import { MemoryCell } from './MemoryCell';
12
+ import { QuantumCell } from './QuantumCell';
13
+
14
+ // Salience threshold for quantum cells
15
+ const QUANTUM_THRESHOLD = 0.7;
16
+
17
+ interface GridConfig {
18
+ columns: number;
19
+ cellWidth: number;
20
+ cellHeight: number;
21
+ horizontalGap: number;
22
+ verticalGap: number;
23
+ }
24
+
25
+ interface MemoryGridProps {
26
+ memories: Memory[];
27
+ memoryType: MemoryType;
28
+ chipWidth: number;
29
+ chipHeight: number;
30
+ selectedMemory: Memory | null;
31
+ onSelectMemory: (memory: Memory | null) => void;
32
+ }
33
+
34
+ // Calculate grid position for a memory at given index
35
+ function calculateGridPosition(
36
+ index: number,
37
+ config: GridConfig,
38
+ sectionOffset: { x: number; y: number; z: number },
39
+ sectionWidth: number
40
+ ): [number, number, number] {
41
+ const { columns, cellWidth, horizontalGap, verticalGap } = config;
42
+
43
+ const col = index % columns;
44
+ const row = Math.floor(index / columns);
45
+
46
+ // Calculate total grid width
47
+ const gridWidth = columns * cellWidth + (columns - 1) * horizontalGap;
48
+ const startX = -gridWidth / 2 + cellWidth / 2;
49
+
50
+ const x = sectionOffset.x + startX + col * (cellWidth + horizontalGap);
51
+ const y = sectionOffset.y - row * (cellWidth * 0.6 + verticalGap);
52
+ const z = sectionOffset.z;
53
+
54
+ return [x, y, z];
55
+ }
56
+
57
+ export function MemoryGrid({
58
+ memories,
59
+ memoryType,
60
+ chipWidth,
61
+ chipHeight,
62
+ selectedMemory,
63
+ onSelectMemory,
64
+ }: MemoryGridProps) {
65
+ const sectionHeight = chipHeight / 3;
66
+ const halfChipHeight = chipHeight / 2;
67
+
68
+ // Grid configuration
69
+ const gridConfig: GridConfig = useMemo(
70
+ () => ({
71
+ columns: 8,
72
+ cellWidth: 1.0,
73
+ cellHeight: 0.6,
74
+ horizontalGap: 0.4,
75
+ verticalGap: 0.3,
76
+ }),
77
+ []
78
+ );
79
+
80
+ // Section offset based on memory type
81
+ const sectionOffset = useMemo(() => {
82
+ switch (memoryType) {
83
+ case 'short_term':
84
+ return {
85
+ x: 0,
86
+ y: halfChipHeight - sectionHeight * 0.35,
87
+ z: 0.2,
88
+ };
89
+ case 'long_term':
90
+ return {
91
+ x: 0,
92
+ y: -halfChipHeight + sectionHeight * 0.65,
93
+ z: 0.2,
94
+ };
95
+ case 'episodic':
96
+ default:
97
+ return {
98
+ x: 0,
99
+ y: 0,
100
+ z: 0.2,
101
+ };
102
+ }
103
+ }, [memoryType, halfChipHeight, sectionHeight]);
104
+
105
+ // Filter memories by type
106
+ const filteredMemories = useMemo(() => {
107
+ return memories.filter((m) => m.type === memoryType);
108
+ }, [memories, memoryType]);
109
+
110
+ // Sort memories by salience (highest first) for better visual hierarchy
111
+ const sortedMemories = useMemo(() => {
112
+ return [...filteredMemories].sort((a, b) => b.salience - a.salience);
113
+ }, [filteredMemories]);
114
+
115
+ return (
116
+ <group>
117
+ {sortedMemories.map((memory, index) => {
118
+ const position = calculateGridPosition(
119
+ index,
120
+ gridConfig,
121
+ sectionOffset,
122
+ chipWidth
123
+ );
124
+
125
+ const isQuantum = memory.salience >= QUANTUM_THRESHOLD;
126
+
127
+ if (isQuantum) {
128
+ return (
129
+ <QuantumCell
130
+ key={memory.id}
131
+ memory={memory}
132
+ position={position}
133
+ onSelect={onSelectMemory}
134
+ isSelected={selectedMemory?.id === memory.id}
135
+ size={1.2}
136
+ />
137
+ );
138
+ }
139
+
140
+ return (
141
+ <MemoryCell
142
+ key={memory.id}
143
+ memory={memory}
144
+ position={position}
145
+ onSelect={onSelectMemory}
146
+ isSelected={selectedMemory?.id === memory.id}
147
+ />
148
+ );
149
+ })}
150
+ </group>
151
+ );
152
+ }
153
+
154
+ // Get grid position for a specific memory (used by pulse animations)
155
+ export function getMemoryGridPosition(
156
+ memory: Memory,
157
+ memories: Memory[],
158
+ chipWidth: number,
159
+ chipHeight: number
160
+ ): [number, number, number] | null {
161
+ const sectionHeight = chipHeight / 3;
162
+ const halfChipHeight = chipHeight / 2;
163
+
164
+ const gridConfig: GridConfig = {
165
+ columns: 8,
166
+ cellWidth: 1.0,
167
+ cellHeight: 0.6,
168
+ horizontalGap: 0.4,
169
+ verticalGap: 0.3,
170
+ };
171
+
172
+ // Get section offset
173
+ let sectionOffset: { x: number; y: number; z: number };
174
+ switch (memory.type) {
175
+ case 'short_term':
176
+ sectionOffset = {
177
+ x: 0,
178
+ y: halfChipHeight - sectionHeight * 0.35,
179
+ z: 0.2,
180
+ };
181
+ break;
182
+ case 'long_term':
183
+ sectionOffset = {
184
+ x: 0,
185
+ y: -halfChipHeight + sectionHeight * 0.65,
186
+ z: 0.2,
187
+ };
188
+ break;
189
+ case 'episodic':
190
+ default:
191
+ sectionOffset = {
192
+ x: 0,
193
+ y: 0,
194
+ z: 0.2,
195
+ };
196
+ }
197
+
198
+ // Find index of this memory in its section (sorted by salience)
199
+ const sectionMemories = memories
200
+ .filter((m) => m.type === memory.type)
201
+ .sort((a, b) => b.salience - a.salience);
202
+
203
+ const index = sectionMemories.findIndex((m) => m.id === memory.id);
204
+ if (index === -1) return null;
205
+
206
+ return calculateGridPosition(index, gridConfig, sectionOffset, chipWidth);
207
+ }
208
+
209
+ // Episodic memories need special handling since they're split left/right of core
210
+ export function EpisodicMemoryGrid({
211
+ memories,
212
+ chipWidth,
213
+ chipHeight,
214
+ coreWidth,
215
+ selectedMemory,
216
+ onSelectMemory,
217
+ }: {
218
+ memories: Memory[];
219
+ chipWidth: number;
220
+ chipHeight: number;
221
+ coreWidth: number;
222
+ selectedMemory: Memory | null;
223
+ onSelectMemory: (memory: Memory | null) => void;
224
+ }) {
225
+ const episodicMemories = useMemo(() => {
226
+ return memories
227
+ .filter((m) => m.type === 'episodic')
228
+ .sort((a, b) => b.salience - a.salience);
229
+ }, [memories]);
230
+
231
+ // Split memories between left and right of core
232
+ const leftMemories = episodicMemories.filter((_, i) => i % 2 === 0);
233
+ const rightMemories = episodicMemories.filter((_, i) => i % 2 === 1);
234
+
235
+ const gridConfig: GridConfig = {
236
+ columns: 3,
237
+ cellWidth: 1.0,
238
+ cellHeight: 0.6,
239
+ horizontalGap: 0.4,
240
+ verticalGap: 0.3,
241
+ };
242
+
243
+ const leftOffset = {
244
+ x: -coreWidth - 2,
245
+ y: 0.5,
246
+ z: 0.2,
247
+ };
248
+
249
+ const rightOffset = {
250
+ x: coreWidth + 2,
251
+ y: 0.5,
252
+ z: 0.2,
253
+ };
254
+
255
+ return (
256
+ <group>
257
+ {/* Left side */}
258
+ {leftMemories.map((memory, index) => {
259
+ const position = calculateGridPosition(
260
+ index,
261
+ gridConfig,
262
+ leftOffset,
263
+ chipWidth / 2 - coreWidth
264
+ );
265
+
266
+ const isQuantum = memory.salience >= QUANTUM_THRESHOLD;
267
+
268
+ if (isQuantum) {
269
+ return (
270
+ <QuantumCell
271
+ key={memory.id}
272
+ memory={memory}
273
+ position={position}
274
+ onSelect={onSelectMemory}
275
+ isSelected={selectedMemory?.id === memory.id}
276
+ size={1.2}
277
+ />
278
+ );
279
+ }
280
+
281
+ return (
282
+ <MemoryCell
283
+ key={memory.id}
284
+ memory={memory}
285
+ position={position}
286
+ onSelect={onSelectMemory}
287
+ isSelected={selectedMemory?.id === memory.id}
288
+ />
289
+ );
290
+ })}
291
+
292
+ {/* Right side */}
293
+ {rightMemories.map((memory, index) => {
294
+ const position = calculateGridPosition(
295
+ index,
296
+ gridConfig,
297
+ rightOffset,
298
+ chipWidth / 2 - coreWidth
299
+ );
300
+
301
+ const isQuantum = memory.salience >= QUANTUM_THRESHOLD;
302
+
303
+ if (isQuantum) {
304
+ return (
305
+ <QuantumCell
306
+ key={memory.id}
307
+ memory={memory}
308
+ position={position}
309
+ onSelect={onSelectMemory}
310
+ isSelected={selectedMemory?.id === memory.id}
311
+ size={1.2}
312
+ />
313
+ );
314
+ }
315
+
316
+ return (
317
+ <MemoryCell
318
+ key={memory.id}
319
+ memory={memory}
320
+ position={position}
321
+ onSelect={onSelectMemory}
322
+ isSelected={selectedMemory?.id === memory.id}
323
+ />
324
+ );
325
+ })}
326
+ </group>
327
+ );
328
+ }
@@ -0,0 +1,316 @@
1
+ 'use client';
2
+
3
+ /**
4
+ * Quantum Cell
5
+ * High-salience memories rendered as rotating Bloch spheres
6
+ * Represents "quantum" memories with special visual treatment
7
+ */
8
+
9
+ import { useRef, useMemo, useState, useCallback } from 'react';
10
+ import { useFrame, ThreeEvent } from '@react-three/fiber';
11
+ import { Html } from '@react-three/drei';
12
+ import * as THREE from 'three';
13
+ import { Memory, MemoryCategory } from '@/types/memory';
14
+
15
+ // Category color mapping (same as MemoryCell)
16
+ const CATEGORY_COLORS: Record<MemoryCategory, string> = {
17
+ architecture: '#06b6d4',
18
+ pattern: '#22c55e',
19
+ preference: '#eab308',
20
+ error: '#ef4444',
21
+ context: '#f97316',
22
+ learning: '#84cc16',
23
+ todo: '#a855f7',
24
+ note: '#3b82f6',
25
+ relationship: '#6366f1',
26
+ custom: '#ec4899',
27
+ };
28
+
29
+ // Category angles for state vector direction (in radians)
30
+ const CATEGORY_ANGLES: Record<MemoryCategory, number> = {
31
+ architecture: 0,
32
+ pattern: Math.PI / 5,
33
+ preference: (2 * Math.PI) / 5,
34
+ error: (3 * Math.PI) / 5,
35
+ context: (4 * Math.PI) / 5,
36
+ learning: Math.PI,
37
+ todo: (6 * Math.PI) / 5,
38
+ note: (7 * Math.PI) / 5,
39
+ relationship: (8 * Math.PI) / 5,
40
+ custom: (9 * Math.PI) / 5,
41
+ };
42
+
43
+ interface QuantumCellProps {
44
+ memory: Memory;
45
+ position: [number, number, number];
46
+ onSelect?: (memory: Memory | null) => void;
47
+ isSelected?: boolean;
48
+ size?: number;
49
+ }
50
+
51
+ export function QuantumCell({
52
+ memory,
53
+ position,
54
+ onSelect,
55
+ isSelected = false,
56
+ size = 1,
57
+ }: QuantumCellProps) {
58
+ const groupRef = useRef<THREE.Group>(null);
59
+ const sphereRef = useRef<THREE.LineSegments>(null);
60
+ const arrowRef = useRef<THREE.Group>(null);
61
+ const glowRef = useRef<THREE.Mesh>(null);
62
+ const interferenceRef = useRef<THREE.Points>(null);
63
+ const [isHovered, setIsHovered] = useState(false);
64
+
65
+ const color = CATEGORY_COLORS[memory.category] || CATEGORY_COLORS.custom;
66
+ const stateAngle = CATEGORY_ANGLES[memory.category] || 0;
67
+
68
+ // Sphere wireframe geometry
69
+ const sphereGeometry = useMemo(() => {
70
+ const sphere = new THREE.SphereGeometry(0.4, 16, 12);
71
+ return new THREE.EdgesGeometry(sphere);
72
+ }, []);
73
+
74
+ // Wireframe material
75
+ const wireMaterial = useMemo(() => {
76
+ return new THREE.LineBasicMaterial({
77
+ color: color,
78
+ transparent: true,
79
+ opacity: 0.6,
80
+ });
81
+ }, [color]);
82
+
83
+ // Glow sphere material
84
+ const glowMaterial = useMemo(() => {
85
+ return new THREE.MeshBasicMaterial({
86
+ color: color,
87
+ transparent: true,
88
+ opacity: 0.15,
89
+ side: THREE.BackSide,
90
+ });
91
+ }, [color]);
92
+
93
+ // Interference pattern particles
94
+ const interferenceGeometry = useMemo(() => {
95
+ const positions = new Float32Array(60 * 3);
96
+ for (let i = 0; i < 60; i++) {
97
+ const theta = Math.random() * Math.PI * 2;
98
+ const phi = Math.acos(2 * Math.random() - 1);
99
+ const r = 0.35 + Math.random() * 0.1;
100
+ positions[i * 3] = r * Math.sin(phi) * Math.cos(theta);
101
+ positions[i * 3 + 1] = r * Math.sin(phi) * Math.sin(theta);
102
+ positions[i * 3 + 2] = r * Math.cos(phi);
103
+ }
104
+ const geometry = new THREE.BufferGeometry();
105
+ geometry.setAttribute('position', new THREE.BufferAttribute(positions, 3));
106
+ return geometry;
107
+ }, []);
108
+
109
+ // Animate rotation and effects
110
+ useFrame((state) => {
111
+ if (!groupRef.current) return;
112
+
113
+ const time = state.clock.elapsedTime;
114
+ const rotationSpeed = 0.3 + memory.salience * 0.3;
115
+
116
+ // Continuous rotation
117
+ groupRef.current.rotation.y = time * rotationSpeed;
118
+ groupRef.current.rotation.x = Math.sin(time * 0.5) * 0.1;
119
+
120
+ // Hover/select: speed up rotation
121
+ if (isHovered || isSelected) {
122
+ groupRef.current.rotation.y = time * rotationSpeed * 2;
123
+ }
124
+
125
+ // Wireframe pulse
126
+ if (sphereRef.current) {
127
+ const mat = sphereRef.current.material as THREE.LineBasicMaterial;
128
+ const pulse = Math.sin(time * 2) * 0.5 + 0.5;
129
+ mat.opacity = 0.4 + pulse * 0.3 + memory.salience * 0.2;
130
+ if (isHovered || isSelected) {
131
+ mat.opacity += 0.2;
132
+ }
133
+ }
134
+
135
+ // Glow pulse
136
+ if (glowRef.current) {
137
+ const mat = glowRef.current.material as THREE.MeshBasicMaterial;
138
+ const pulse = Math.sin(time * 1.5) * 0.5 + 0.5;
139
+ mat.opacity = 0.1 + pulse * 0.15;
140
+ glowRef.current.scale.setScalar(1.2 + pulse * 0.1);
141
+ }
142
+
143
+ // Interference shimmer
144
+ if (interferenceRef.current) {
145
+ const positions = interferenceRef.current.geometry.attributes.position.array as Float32Array;
146
+ for (let i = 0; i < positions.length / 3; i++) {
147
+ const idx = i * 3;
148
+ const shimmer = Math.sin(time * 3 + i * 0.5) * 0.02;
149
+ // Just modify radius slightly for shimmer effect
150
+ const x = positions[idx];
151
+ const y = positions[idx + 1];
152
+ const z = positions[idx + 2];
153
+ const r = Math.sqrt(x * x + y * y + z * z);
154
+ const newR = 0.38 + shimmer;
155
+ const scale = newR / r;
156
+ positions[idx] = x * scale;
157
+ positions[idx + 1] = y * scale;
158
+ positions[idx + 2] = z * scale;
159
+ }
160
+ interferenceRef.current.geometry.attributes.position.needsUpdate = true;
161
+ }
162
+ });
163
+
164
+ const handleClick = useCallback(
165
+ (e: ThreeEvent<MouseEvent>) => {
166
+ e.stopPropagation();
167
+ onSelect?.(isSelected ? null : memory);
168
+ },
169
+ [memory, onSelect, isSelected]
170
+ );
171
+
172
+ const handlePointerOver = useCallback((e: ThreeEvent<PointerEvent>) => {
173
+ e.stopPropagation();
174
+ setIsHovered(true);
175
+ document.body.style.cursor = 'pointer';
176
+ }, []);
177
+
178
+ const handlePointerOut = useCallback(() => {
179
+ setIsHovered(false);
180
+ document.body.style.cursor = 'auto';
181
+ }, []);
182
+
183
+ return (
184
+ <group position={position} scale={size}>
185
+ <group
186
+ ref={groupRef}
187
+ onClick={handleClick}
188
+ onPointerOver={handlePointerOver}
189
+ onPointerOut={handlePointerOut}
190
+ >
191
+ {/* Wireframe Bloch sphere */}
192
+ <lineSegments ref={sphereRef} geometry={sphereGeometry} material={wireMaterial} />
193
+
194
+ {/* Axis lines */}
195
+ <AxisLines color={color} />
196
+
197
+ {/* State vector arrow */}
198
+ <group ref={arrowRef} rotation={[0, stateAngle, Math.PI / 4]}>
199
+ <StateVector color={color} />
200
+ </group>
201
+
202
+ {/* Glow sphere */}
203
+ <mesh ref={glowRef}>
204
+ <sphereGeometry args={[0.5, 12, 8]} />
205
+ <primitive object={glowMaterial} />
206
+ </mesh>
207
+
208
+ {/* Interference pattern particles */}
209
+ <points ref={interferenceRef} geometry={interferenceGeometry}>
210
+ <pointsMaterial
211
+ color={color}
212
+ size={0.03}
213
+ transparent
214
+ opacity={0.4}
215
+ sizeAttenuation
216
+ />
217
+ </points>
218
+
219
+ {/* Clickable invisible sphere */}
220
+ <mesh visible={false}>
221
+ <sphereGeometry args={[0.5, 8, 6]} />
222
+ <meshBasicMaterial transparent opacity={0} />
223
+ </mesh>
224
+ </group>
225
+
226
+ {/* Selection ring */}
227
+ {isSelected && (
228
+ <mesh rotation={[Math.PI / 2, 0, 0]} position={[0, 0, 0]}>
229
+ <ringGeometry args={[0.55, 0.6, 32]} />
230
+ <meshBasicMaterial color="#ffffff" transparent opacity={0.7} side={THREE.DoubleSide} />
231
+ </mesh>
232
+ )}
233
+
234
+ {/* Quantum label */}
235
+ <Html
236
+ position={[0, -0.6, 0]}
237
+ center
238
+ style={{ pointerEvents: 'none' }}
239
+ >
240
+ <div className="text-[8px] font-mono text-amber-400/60 whitespace-nowrap">
241
+ |Q{memory.id}⟩
242
+ </div>
243
+ </Html>
244
+
245
+ {/* Tooltip on hover */}
246
+ {isHovered && (
247
+ <Html
248
+ position={[0, 0.7, 0]}
249
+ center
250
+ style={{
251
+ pointerEvents: 'none',
252
+ transform: 'translateY(-100%)',
253
+ }}
254
+ >
255
+ <div className="bg-slate-900/95 border border-amber-600/50 rounded-lg px-3 py-2 text-xs max-w-[220px] backdrop-blur-sm shadow-lg">
256
+ <div className="flex items-center gap-2 mb-1">
257
+ <span className="text-amber-400 text-[10px]">QUANTUM</span>
258
+ <span className="text-slate-500">|</span>
259
+ <span className="text-slate-400">{Math.round(memory.salience * 100)}% salience</span>
260
+ </div>
261
+ <div className="font-semibold text-white truncate">{memory.title}</div>
262
+ <div className="text-slate-400 mt-1 flex items-center gap-2">
263
+ <span
264
+ className="w-2 h-2 rounded-full"
265
+ style={{ backgroundColor: color }}
266
+ />
267
+ <span className="capitalize">{memory.category}</span>
268
+ </div>
269
+ </div>
270
+ </Html>
271
+ )}
272
+ </group>
273
+ );
274
+ }
275
+
276
+ // Axis lines (x, y, z) inside the Bloch sphere
277
+ function AxisLines({ color }: { color: string }) {
278
+ const geometry = useMemo(() => {
279
+ const points = [
280
+ // X axis
281
+ new THREE.Vector3(-0.35, 0, 0),
282
+ new THREE.Vector3(0.35, 0, 0),
283
+ // Y axis
284
+ new THREE.Vector3(0, -0.35, 0),
285
+ new THREE.Vector3(0, 0.35, 0),
286
+ // Z axis
287
+ new THREE.Vector3(0, 0, -0.35),
288
+ new THREE.Vector3(0, 0, 0.35),
289
+ ];
290
+ return new THREE.BufferGeometry().setFromPoints(points);
291
+ }, []);
292
+
293
+ return (
294
+ <lineSegments geometry={geometry}>
295
+ <lineBasicMaterial color={color} transparent opacity={0.3} />
296
+ </lineSegments>
297
+ );
298
+ }
299
+
300
+ // State vector arrow pointing in a direction
301
+ function StateVector({ color }: { color: string }) {
302
+ return (
303
+ <group>
304
+ {/* Arrow shaft */}
305
+ <mesh position={[0, 0.15, 0]}>
306
+ <cylinderGeometry args={[0.02, 0.02, 0.3, 8]} />
307
+ <meshBasicMaterial color={color} />
308
+ </mesh>
309
+ {/* Arrow head */}
310
+ <mesh position={[0, 0.32, 0]}>
311
+ <coneGeometry args={[0.05, 0.1, 8]} />
312
+ <meshBasicMaterial color={color} />
313
+ </mesh>
314
+ </group>
315
+ );
316
+ }