TheGreatUnknown commited on
Commit
9566e84
·
verified ·
1 Parent(s): de5eeaf

Create script.js

Browse files
Files changed (1) hide show
  1. script.js +1366 -0
script.js ADDED
@@ -0,0 +1,1366 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import { config } from './config.js';
2
+ import * as THREE from 'three';
3
+ import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
4
+
5
+ // Main application state
6
+ const state = {
7
+ currentMode: 'sonw',
8
+ evolutionInProgress: false,
9
+ recursionDepth: 3,
10
+ particles: [],
11
+ metrics: {
12
+ symbolic: 20,
13
+ quantum: 15,
14
+ holographic: 10,
15
+ meta: 5
16
+ },
17
+ // Multiplayer state
18
+ multiplayer: {
19
+ connected: false,
20
+ username: '',
21
+ userId: '',
22
+ userColor: '',
23
+ researchers: {},
24
+ sharedAnalyses: []
25
+ }
26
+ };
27
+
28
+ // Initialize WebsimSocket for multiplayer
29
+ const room = new WebsimSocket();
30
+
31
+ // DOM elements
32
+ const visualizationEl = document.getElementById('visualization');
33
+ const conceptInput = document.getElementById('conceptInput');
34
+ const symbolSelector = document.getElementById('symbolSelector');
35
+ const outputEl = document.getElementById('output');
36
+ const statusEl = document.getElementById('statusDisplay');
37
+ const depthSlider = document.getElementById('recursionDepth');
38
+ const depthValueEl = document.getElementById('depthValue');
39
+ const systemButtons = ['sonwBtn', 'afterthoughtBtn', 'cognitiveBtn', 'integratedBtn'].map(id => document.getElementById(id));
40
+ const userCountEl = document.getElementById('user-count');
41
+ const researchersEl = document.getElementById('researchers');
42
+ const shareBtn = document.getElementById('shareBtn');
43
+ const syncBtn = document.getElementById('syncBtn');
44
+ const sharedAnalysesListEl = document.getElementById('shared-analyses-list');
45
+ const userCursorsEl = document.getElementById('user-cursors');
46
+ const notificationEl = document.getElementById('notification');
47
+
48
+ // Three.js setup
49
+ let scene, camera, renderer, controls;
50
+ let particles, connections;
51
+
52
+ const initVisualization = () => {
53
+ // Setup Three.js scene
54
+ scene = new THREE.Scene();
55
+ scene.background = new THREE.Color(config.visualization.backgroundColor);
56
+
57
+ // Setup camera
58
+ camera = new THREE.PerspectiveCamera(75, visualizationEl.clientWidth / visualizationEl.clientHeight, 0.1, 2000);
59
+ camera.position.z = 300;
60
+
61
+ // Setup renderer
62
+ renderer = new THREE.WebGLRenderer({ antialias: true });
63
+ renderer.setSize(visualizationEl.clientWidth, visualizationEl.clientHeight);
64
+ visualizationEl.appendChild(renderer.domElement);
65
+
66
+ // Add orbit controls
67
+ controls = new OrbitControls(camera, renderer.domElement);
68
+ controls.enableDamping = true;
69
+ controls.dampingFactor = 0.05;
70
+
71
+ // Create particles group
72
+ particles = new THREE.Group();
73
+ scene.add(particles);
74
+
75
+ // Create connections group
76
+ connections = new THREE.Group();
77
+ scene.add(connections);
78
+
79
+ // Add grid for reference
80
+ const gridHelper = new THREE.GridHelper(400, 20, 0x404040, 0x404040);
81
+ gridHelper.position.y = -100;
82
+ scene.add(gridHelper);
83
+
84
+ // Add ambient light
85
+ const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
86
+ scene.add(ambientLight);
87
+
88
+ // Add point light
89
+ const pointLight = new THREE.PointLight(0xffffff, 1);
90
+ pointLight.position.set(0, 150, 200);
91
+ scene.add(pointLight);
92
+
93
+ // Initialize particles based on current mode
94
+ createParticleSystem(state.currentMode);
95
+
96
+ // Start animation loop
97
+ animate();
98
+
99
+ // Handle window resize
100
+ window.addEventListener('resize', onWindowResize);
101
+ };
102
+
103
+ const onWindowResize = () => {
104
+ camera.aspect = visualizationEl.clientWidth / visualizationEl.clientHeight;
105
+ camera.updateProjectionMatrix();
106
+ renderer.setSize(visualizationEl.clientWidth, visualizationEl.clientHeight);
107
+ };
108
+
109
+ const createFractalNetworkPattern = (geometry, material, modeConfig) => {
110
+ // Create network-like distribution with fractal properties
111
+ for (let i = 0; i < config.visualization.particleCount; i++) {
112
+ const particle = new THREE.Mesh(geometry, material);
113
+
114
+ // Position in fractal network structure
115
+ const fractalDepth = Math.floor(Math.random() * 3) + 1;
116
+ const angleXY = Math.random() * Math.PI * 2;
117
+ const radiusXY = 20 + Math.random() * modeConfig.particleSpread * 0.5;
118
+
119
+ // Use fractal positioning algorithm
120
+ const fractalScale = 1 / (fractalDepth * 0.5);
121
+ particle.position.x = Math.cos(angleXY) * radiusXY * fractalScale;
122
+ particle.position.y = (fractalDepth * 40) - 60;
123
+ particle.position.z = Math.sin(angleXY) * radiusXY * fractalScale;
124
+
125
+ // Add controlled fractal variation
126
+ particle.position.x += (Math.random() - 0.5) * 40 * fractalScale;
127
+ particle.position.z += (Math.random() - 0.5) * 40 * fractalScale;
128
+
129
+ // Store velocity and fractal properties for animation
130
+ particle.userData = {
131
+ velocity: new THREE.Vector3(
132
+ (Math.random() - 0.5) * 0.2 * fractalScale,
133
+ (Math.random() - 0.5) * 0.1 * fractalScale,
134
+ (Math.random() - 0.5) * 0.2 * fractalScale
135
+ ),
136
+ originalPosition: particle.position.clone(),
137
+ fractalDepth: fractalDepth
138
+ };
139
+
140
+ particles.add(particle);
141
+ state.particles.push(particle);
142
+ }
143
+ };
144
+
145
+ const createQuantumFieldPattern = (geometry, material, modeConfig) => {
146
+ // Create quantum field-like distribution
147
+ for (let i = 0; i < config.visualization.particleCount; i++) {
148
+ const particle = new THREE.Mesh(geometry, material);
149
+
150
+ // Position in a spherical field with superposition properties
151
+ const phi = Math.acos(-1 + 2 * Math.random());
152
+ const theta = 2 * Math.PI * Math.random();
153
+ const radius = 50 + Math.random() * modeConfig.particleSpread * 0.6;
154
+
155
+ particle.position.x = radius * Math.sin(phi) * Math.cos(theta);
156
+ particle.position.y = radius * Math.sin(phi) * Math.sin(theta);
157
+ particle.position.z = radius * Math.cos(phi);
158
+
159
+ // Quantum properties for animation
160
+ const superposition = Math.random() > 0.5;
161
+ const entanglementFactor = Math.random();
162
+ const orbitalAxis = new THREE.Vector3(
163
+ Math.random() - 0.5,
164
+ Math.random() - 0.5,
165
+ Math.random() - 0.5
166
+ ).normalize();
167
+
168
+ particle.userData = {
169
+ velocity: new THREE.Vector3(
170
+ (Math.random() - 0.5) * 0.1,
171
+ (Math.random() - 0.5) * 0.1,
172
+ (Math.random() - 0.5) * 0.1
173
+ ),
174
+ originalPosition: particle.position.clone(),
175
+ superposition: superposition,
176
+ entanglementFactor: entanglementFactor,
177
+ orbitalAxis: orbitalAxis,
178
+ orbitalSpeed: (Math.random() * 0.01) + 0.005
179
+ };
180
+
181
+ particles.add(particle);
182
+ state.particles.push(particle);
183
+ }
184
+ };
185
+
186
+ const createFractalPattern = (geometry, material, modeConfig) => {
187
+ // Create fractal-like distribution for Holographic Intelligence
188
+ // Use recursive patterns with self-similarity
189
+
190
+ const createFractalPoint = (centerPoint, scale, depth) => {
191
+ if (depth <= 0 || state.particles.length >= config.visualization.particleCount) return;
192
+
193
+ // Create center particle
194
+ const particle = new THREE.Mesh(geometry, material);
195
+ particle.position.copy(centerPoint);
196
+
197
+ // Add some variation
198
+ particle.position.x += (Math.random() - 0.5) * scale * 0.2;
199
+ particle.position.y += (Math.random() - 0.5) * scale * 0.2;
200
+ particle.position.z += (Math.random() - 0.5) * scale * 0.2;
201
+
202
+ particle.userData = {
203
+ velocity: new THREE.Vector3(
204
+ (Math.random() - 0.5) * 0.1,
205
+ (Math.random() - 0.5) * 0.1,
206
+ (Math.random() - 0.5) * 0.1
207
+ ),
208
+ originalPosition: particle.position.clone(),
209
+ fractalDepth: depth
210
+ };
211
+
212
+ particles.add(particle);
213
+ state.particles.push(particle);
214
+
215
+ // Create sub-structures (branches)
216
+ const branchCount = 6;
217
+ const newScale = scale * 0.6;
218
+
219
+ for (let i = 0; i < branchCount; i++) {
220
+ // Create points in a geodesic-like pattern
221
+ const angle1 = (i / branchCount) * Math.PI * 2;
222
+ const angle2 = Math.PI / 4; // Fixed angle from center
223
+
224
+ const newX = centerPoint.x + Math.sin(angle1) * Math.cos(angle2) * scale;
225
+ const newY = centerPoint.y + Math.sin(angle1) * Math.sin(angle2) * scale;
226
+ const newZ = centerPoint.z + Math.cos(angle1) * scale;
227
+
228
+ const newPoint = new THREE.Vector3(newX, newY, newZ);
229
+
230
+ // Recursive call for each branch
231
+ createFractalPoint(newPoint, newScale, depth - 1);
232
+ }
233
+ };
234
+
235
+ // Start the recursive fractal generation from center
236
+ createFractalPoint(new THREE.Vector3(0, 0, 0), modeConfig.particleSpread * 0.3, 3);
237
+ };
238
+
239
+ const createHolisticPattern = (geometry, material, modeConfig) => {
240
+ // Create an integrated pattern combining aspects of all systems
241
+
242
+ // First layer: LLML networked structure (30% of particles)
243
+ const llmlCount = Math.floor(config.visualization.particleCount * 0.3);
244
+ for (let i = 0; i < llmlCount; i++) {
245
+ const particle = new THREE.Mesh(geometry, material);
246
+
247
+ // Layered network structure
248
+ const layerIndex = Math.floor(Math.random() * 3);
249
+ const angleXY = Math.random() * Math.PI * 2;
250
+ const radiusXY = 30 + Math.random() * 60;
251
+
252
+ particle.position.x = Math.cos(angleXY) * radiusXY;
253
+ particle.position.y = (layerIndex * 40) - 40;
254
+ particle.position.z = Math.sin(angleXY) * radiusXY;
255
+
256
+ particle.userData = {
257
+ velocity: new THREE.Vector3(
258
+ (Math.random() - 0.5) * 0.15,
259
+ (Math.random() - 0.5) * 0.05,
260
+ (Math.random() - 0.5) * 0.15
261
+ ),
262
+ originalPosition: particle.position.clone(),
263
+ system: 'llml'
264
+ };
265
+
266
+ particles.add(particle);
267
+ state.particles.push(particle);
268
+ }
269
+
270
+ // Second layer: QGA quantum field (30% of particles)
271
+ const qgaCount = Math.floor(config.visualization.particleCount * 0.3);
272
+ for (let i = 0; i < qgaCount; i++) {
273
+ const particle = new THREE.Mesh(geometry, material);
274
+
275
+ // Spherical field distribution
276
+ const phi = Math.acos(-1 + 2 * Math.random());
277
+ const theta = 2 * Math.PI * Math.random();
278
+ const radius = 80 + Math.random() * 70;
279
+
280
+ particle.position.x = radius * Math.sin(phi) * Math.cos(theta);
281
+ particle.position.y = radius * Math.sin(phi) * Math.sin(theta);
282
+ particle.position.z = radius * Math.cos(phi);
283
+
284
+ const orbitalAxis = new THREE.Vector3(
285
+ Math.random() - 0.5,
286
+ Math.random() - 0.5,
287
+ Math.random() - 0.5
288
+ ).normalize();
289
+
290
+ particle.userData = {
291
+ velocity: new THREE.Vector3(
292
+ (Math.random() - 0.5) * 0.1,
293
+ (Math.random() - 0.5) * 0.1,
294
+ (Math.random() - 0.5) * 0.1
295
+ ),
296
+ originalPosition: particle.position.clone(),
297
+ orbitalAxis: orbitalAxis,
298
+ orbitalSpeed: (Math.random() * 0.01) + 0.005,
299
+ system: 'qga'
300
+ };
301
+
302
+ particles.add(particle);
303
+ state.particles.push(particle);
304
+ }
305
+
306
+ // Third layer: Holographic fractal points (remaining particles)
307
+ const holoCount = config.visualization.particleCount - llmlCount - qgaCount;
308
+
309
+ // Generate a few fractal seed points
310
+ for (let i = 0; i < 5; i++) {
311
+ const centerPoint = new THREE.Vector3(
312
+ (Math.random() - 0.5) * 150,
313
+ (Math.random() - 0.5) * 150,
314
+ (Math.random() - 0.5) * 150
315
+ );
316
+
317
+ // Create mini fractal clusters
318
+ for (let j = 0; j < holoCount / 5; j++) {
319
+ const particle = new THREE.Mesh(geometry, material);
320
+
321
+ // Position in a cluster around the center point
322
+ const fractalRadius = 10 + Math.random() * 25;
323
+ const fractalPhi = Math.acos(-1 + 2 * Math.random());
324
+ const fractalTheta = 2 * Math.PI * Math.random();
325
+
326
+ particle.position.x = centerPoint.x + fractalRadius * Math.sin(fractalPhi) * Math.cos(fractalTheta);
327
+ particle.position.y = centerPoint.y + fractalRadius * Math.sin(fractalPhi) * Math.sin(fractalTheta);
328
+ particle.position.z = centerPoint.z + fractalRadius * Math.cos(fractalPhi);
329
+
330
+ particle.userData = {
331
+ velocity: new THREE.Vector3(
332
+ (Math.random() - 0.5) * 0.1,
333
+ (Math.random() - 0.5) * 0.1,
334
+ (Math.random() - 0.5) * 0.1
335
+ ),
336
+ originalPosition: particle.position.clone(),
337
+ fractalCenter: centerPoint.clone(),
338
+ system: 'holographic'
339
+ };
340
+
341
+ particles.add(particle);
342
+ state.particles.push(particle);
343
+ }
344
+ }
345
+ };
346
+
347
+ const createConnections = (modeConfig) => {
348
+ // Create connections between particles based on proximity
349
+ const linesMaterial = new THREE.LineBasicMaterial({
350
+ color: config.visualization.connectionColor,
351
+ transparent: true,
352
+ opacity: 0.3
353
+ });
354
+
355
+ const particlePositions = state.particles.map(p => p.position);
356
+ const threshold = config.visualization.connectionThreshold * modeConfig.connectionDensity;
357
+
358
+ for (let i = 0; i < particlePositions.length; i++) {
359
+ for (let j = i + 1; j < particlePositions.length; j++) {
360
+ const distance = particlePositions[i].distanceTo(particlePositions[j]);
361
+
362
+ if (distance < threshold) {
363
+ // Create connection between these particles
364
+ const lineGeometry = new THREE.BufferGeometry().setFromPoints([
365
+ particlePositions[i],
366
+ particlePositions[j]
367
+ ]);
368
+
369
+ const line = new THREE.Line(lineGeometry, linesMaterial);
370
+ connections.add(line);
371
+
372
+ // Link the connection to particles
373
+ line.userData = {
374
+ particleIndexA: i,
375
+ particleIndexB: j
376
+ };
377
+ }
378
+ }
379
+ }
380
+ };
381
+
382
+ const updateConnections = () => {
383
+ // Update all connection lines to match particle positions
384
+ connections.children.forEach(line => {
385
+ const { particleIndexA, particleIndexB } = line.userData;
386
+
387
+ if (particleIndexA < state.particles.length && particleIndexB < state.particles.length) {
388
+ const posA = state.particles[particleIndexA].position;
389
+ const posB = state.particles[particleIndexB].position;
390
+
391
+ const positions = line.geometry.attributes.position.array;
392
+
393
+ // Update positions
394
+ positions[0] = posA.x;
395
+ positions[1] = posA.y;
396
+ positions[2] = posA.z;
397
+ positions[3] = posB.x;
398
+ positions[4] = posB.y;
399
+ positions[5] = posB.z;
400
+
401
+ line.geometry.attributes.position.needsUpdate = true;
402
+ }
403
+ });
404
+ };
405
+
406
+ const animate = () => {
407
+ requestAnimationFrame(animate);
408
+
409
+ // Animate particles based on mode
410
+ animateParticles();
411
+
412
+ // Update connections
413
+ updateConnections();
414
+
415
+ // Update orbital controls
416
+ controls.update();
417
+
418
+ // Render scene
419
+ renderer.render(scene, camera);
420
+ };
421
+
422
+ const animateParticles = () => {
423
+ // Apply different animation based on current mode
424
+ const mode = state.currentMode;
425
+
426
+ switch(mode) {
427
+ case 'sonw':
428
+ // Network-like movement
429
+ animateSONWParticles();
430
+ break;
431
+
432
+ case 'afterthought':
433
+ // Quantum field movement
434
+ animateQGAParticles();
435
+ break;
436
+
437
+ case 'cognitive':
438
+ // Fractal pattern movement
439
+ animateHolographicParticles();
440
+ break;
441
+
442
+ case 'integrated':
443
+ // Combined animation of all systems
444
+ animateIntegratedParticles();
445
+ break;
446
+ }
447
+ };
448
+
449
+ const animateSONWParticles = () => {
450
+ state.particles.forEach(particle => {
451
+ // Gentle oscillation around original position
452
+ const origPos = particle.userData.originalPosition;
453
+ const velocity = particle.userData.velocity;
454
+
455
+ // Move with velocity
456
+ particle.position.x += velocity.x;
457
+ particle.position.y += velocity.y;
458
+ particle.position.z += velocity.z;
459
+
460
+ // Apply a force back toward original position
461
+ const diffX = origPos.x - particle.position.x;
462
+ const diffY = origPos.y - particle.position.y;
463
+ const diffZ = origPos.z - particle.position.z;
464
+
465
+ velocity.x += diffX * 0.01;
466
+ velocity.y += diffY * 0.01;
467
+ velocity.z += diffZ * 0.01;
468
+
469
+ // Dampen velocity
470
+ velocity.x *= 0.98;
471
+ velocity.y *= 0.98;
472
+ velocity.z *= 0.98;
473
+ });
474
+ };
475
+
476
+ const animateQGAParticles = () => {
477
+ state.particles.forEach(particle => {
478
+ // Quantum-inspired orbital movement
479
+ const velocity = particle.userData.velocity;
480
+ const orbitalAxis = particle.userData.orbitalAxis;
481
+ const orbitalSpeed = particle.userData.orbitalSpeed;
482
+
483
+ // Apply orbital rotation
484
+ const rotationMatrix = new THREE.Matrix4().makeRotationAxis(orbitalAxis, orbitalSpeed);
485
+ particle.position.applyMatrix4(rotationMatrix);
486
+
487
+ // Add some random quantum fluctuation
488
+ velocity.x += (Math.random() - 0.5) * 0.02;
489
+ velocity.y += (Math.random() - 0.5) * 0.02;
490
+ velocity.z += (Math.random() - 0.5) * 0.02;
491
+
492
+ // Apply velocity with strong damping (quantum fluctuations don't accumulate)
493
+ particle.position.x += velocity.x;
494
+ particle.position.y += velocity.y;
495
+ particle.position.z += velocity.z;
496
+
497
+ // Strong damping for stability
498
+ velocity.x *= 0.8;
499
+ velocity.y *= 0.8;
500
+ velocity.z *= 0.8;
501
+ });
502
+ };
503
+
504
+ const animateHolographicParticles = () => {
505
+ state.particles.forEach(particle => {
506
+ // Fractal pulsing movement
507
+ const velocity = particle.userData.velocity;
508
+ const fractalDepth = particle.userData.fractalDepth || 1;
509
+
510
+ // Deeper fractal levels move less
511
+ const depthFactor = 1 / (fractalDepth * 0.5);
512
+
513
+ // Apply a pulsing movement
514
+ const time = Date.now() * 0.001;
515
+ const pulseFactor = Math.sin(time * 0.5) * 0.2 * depthFactor;
516
+
517
+ // Move with velocity and pulse
518
+ particle.position.x += velocity.x + (particle.position.x * pulseFactor);
519
+ particle.position.y += velocity.y + (particle.position.y * pulseFactor);
520
+ particle.position.z += velocity.z + (particle.position.z * pulseFactor);
521
+
522
+ // Apply a centering force to maintain overall structure
523
+ const centeringForce = 0.001 * depthFactor;
524
+ velocity.x -= particle.position.x * centeringForce;
525
+ velocity.y -= particle.position.y * centeringForce;
526
+ velocity.z -= particle.position.z * centeringForce;
527
+
528
+ // Dampen velocity
529
+ velocity.x *= 0.95;
530
+ velocity.y *= 0.95;
531
+ velocity.z *= 0.95;
532
+ });
533
+ };
534
+
535
+ const animateIntegratedParticles = () => {
536
+ state.particles.forEach(particle => {
537
+ // Apply animation based on the particle's system
538
+ const system = particle.userData.system;
539
+
540
+ if (system === 'llml') {
541
+ // Network node behavior
542
+ const origPos = particle.userData.originalPosition;
543
+ const velocity = particle.userData.velocity;
544
+
545
+ particle.position.x += velocity.x;
546
+ particle.position.y += velocity.y;
547
+ particle.position.z += velocity.z;
548
+
549
+ const diffX = origPos.x - particle.position.x;
550
+ const diffY = origPos.y - particle.position.y;
551
+ const diffZ = origPos.z - particle.position.z;
552
+
553
+ velocity.x += diffX * 0.01;
554
+ velocity.y += diffY * 0.01;
555
+ velocity.z += diffZ * 0.01;
556
+
557
+ velocity.x *= 0.98;
558
+ velocity.y *= 0.98;
559
+ velocity.z *= 0.98;
560
+
561
+ } else if (system === 'qga') {
562
+ // Quantum field behavior
563
+ const velocity = particle.userData.velocity;
564
+ const orbitalAxis = particle.userData.orbitalAxis;
565
+ const orbitalSpeed = particle.userData.orbitalSpeed;
566
+
567
+ const rotationMatrix = new THREE.Matrix4().makeRotationAxis(orbitalAxis, orbitalSpeed);
568
+ particle.position.applyMatrix4(rotationMatrix);
569
+
570
+ velocity.x += (Math.random() - 0.5) * 0.02;
571
+ velocity.y += (Math.random() - 0.5) * 0.02;
572
+ velocity.z += (Math.random() - 0.5) * 0.02;
573
+
574
+ particle.position.x += velocity.x;
575
+ particle.position.y += velocity.y;
576
+ particle.position.z += velocity.z;
577
+
578
+ velocity.x *= 0.8;
579
+ velocity.y *= 0.8;
580
+ velocity.z *= 0.8;
581
+
582
+ } else if (system === 'holographic') {
583
+ // Fractal behavior
584
+ const velocity = particle.userData.velocity;
585
+ const fractalCenter = particle.userData.fractalCenter;
586
+
587
+ // Pulsing movement
588
+ const time = Date.now() * 0.001;
589
+ const pulseFactor = Math.sin(time * 0.5) * 0.2;
590
+
591
+ // Vector from fractal center to particle
592
+ const dirX = particle.position.x - fractalCenter.x;
593
+ const dirY = particle.position.y - fractalCenter.y;
594
+ const dirZ = particle.position.z - fractalCenter.z;
595
+
596
+ // Apply pulse along this direction
597
+ particle.position.x += velocity.x + (dirX * pulseFactor * 0.01);
598
+ particle.position.y += velocity.y + (dirY * pulseFactor * 0.01);
599
+ particle.position.z += velocity.z + (dirZ * pulseFactor * 0.01);
600
+
601
+ // Apply a centering force to maintain cluster
602
+ const centeringForce = 0.001;
603
+ velocity.x -= dirX * centeringForce;
604
+ velocity.y -= dirY * centeringForce;
605
+ velocity.z -= dirZ * centeringForce;
606
+
607
+ velocity.x *= 0.95;
608
+ velocity.y *= 0.95;
609
+ velocity.z *= 0.95;
610
+ }
611
+ });
612
+
613
+ // Add emergent behavior for the integrated system
614
+ // This creates interactions between the different systems
615
+
616
+ // Slow rotation of the entire system
617
+ particles.rotation.y += 0.0005;
618
+ connections.rotation.y += 0.0005;
619
+ };
620
+
621
+ const createParticleSystem = (mode) => {
622
+ // Clear existing particles and connections
623
+ while(particles.children.length > 0) {
624
+ particles.remove(particles.children[0]);
625
+ }
626
+
627
+ while(connections.children.length > 0) {
628
+ connections.remove(connections.children[0]);
629
+ }
630
+
631
+ // Get mode configuration
632
+ const modeConfig = config.modes[mode];
633
+
634
+ // Create particles
635
+ const particleGeometry = new THREE.SphereGeometry(config.visualization.nodeSize, 16, 16);
636
+ const particleMaterial = new THREE.MeshPhongMaterial({
637
+ color: new THREE.Color(modeConfig.color),
638
+ emissive: new THREE.Color(modeConfig.color).multiplyScalar(0.5),
639
+ shininess: 50
640
+ });
641
+
642
+ // Create particles based on pattern type
643
+ state.particles = [];
644
+
645
+ switch(modeConfig.patternType) {
646
+ case 'fractal-network':
647
+ // Create fractal-network pattern (SONW)
648
+ createFractalNetworkPattern(particleGeometry, particleMaterial, modeConfig);
649
+ break;
650
+
651
+ case 'quantum-field':
652
+ // Create quantum field pattern (Afterthought)
653
+ createQuantumFieldPattern(particleGeometry, particleMaterial, modeConfig);
654
+ break;
655
+
656
+ case 'holographic':
657
+ // Create holographic pattern (Cognitive)
658
+ createFractalPattern(particleGeometry, particleMaterial, modeConfig);
659
+ break;
660
+
661
+ case 'holistic':
662
+ // Create holistic pattern (Integrated)
663
+ createHolisticPattern(particleGeometry, particleMaterial, modeConfig);
664
+ break;
665
+ }
666
+
667
+ // Create connections between particles
668
+ createConnections(modeConfig);
669
+ };
670
+
671
+ const handleSymbolicProcess = async () => {
672
+ if (state.evolutionInProgress) return;
673
+
674
+ // Get symbolic expression from input or selector
675
+ let symbolicExpression = conceptInput.value.trim();
676
+
677
+ if (!symbolicExpression) {
678
+ // Use selected expression from dropdown
679
+ const selectedKey = symbolSelector.value;
680
+ symbolicExpression = config.symbolicExpressions[selectedKey].expression;
681
+ }
682
+
683
+ // Start processing animation
684
+ updateStatus(`Processing symbolic expression: ${symbolicExpression}`);
685
+ outputEl.innerHTML = `<p>Analyzing ${symbolicExpression}...</p>`;
686
+ visualizationEl.classList.add('recursing');
687
+
688
+ // Simulate processing with the current system
689
+ await new Promise(resolve => setTimeout(resolve, 1500));
690
+
691
+ // Generate analysis
692
+ await generateSymbolicAnalysis(symbolicExpression);
693
+
694
+ // End animation
695
+ visualizationEl.classList.remove('recursing');
696
+ };
697
+
698
+ const generateSymbolicAnalysis = async (expression) => {
699
+ // Using the LLM to generate a better response
700
+ let analysisOutput = '';
701
+
702
+ try {
703
+ // Prepare prompt for LLM
704
+ const systemPrompt = `You are the Meta-Cosmic-Weaver, an advanced AI that integrates SONW (Symbolicentric Orbital Neural Weave),
705
+ Afterthought Quantum Conceptualization, and Cognitive Engine components into a Triadic Architecture for recursive intelligence.
706
+
707
+ Analyze the symbolic LLML expression provided and generate 3 insights corresponding to these three levels:
708
+
709
+ Insight 1 (SONW): Analyze the expression as a fractal-symbolic framework using algebraic reasoning structures and neural-symbolic integration.
710
+
711
+ Insight 2 (Afterthought): Provide a quantum-inspired interpretation that explores superposition, entanglement, and probabilistic consciousness.
712
+
713
+ Insight 3 (Cognitive): Offer a meta-mathematical interpretation that treats the expression as an executable semantic transformation protocol.
714
+
715
+ Use terminology from: quantum mechanics, geometric algebra, fractal mathematics, neural-symbolic integration, and recursive symbolic systems.
716
+ Each insight should build upon the previous one with increasing sophistication.`;
717
+
718
+ const messages = [
719
+ {
720
+ role: "system",
721
+ content: systemPrompt
722
+ },
723
+ {
724
+ role: "user",
725
+ content: `Generate three progressive insights for the LLML symbolic expression: ${expression}`
726
+ }
727
+ ];
728
+
729
+ // Generate response using LLM
730
+ const completion = await websim.chat.completions.create({
731
+ messages: messages
732
+ });
733
+
734
+ analysisOutput = completion.content;
735
+ } catch (error) {
736
+ // Fallback to template-based generation
737
+ console.log("Using template-based generation instead of LLM");
738
+ analysisOutput = generateTemplateBasedAnalysis(expression);
739
+ }
740
+
741
+ // Display output with animation
742
+ outputEl.innerHTML = ''; // Clear output
743
+
744
+ // Split by paragraphs and display with delay
745
+ const paragraphs = analysisOutput.split('\n\n');
746
+ let insightCounter = 1;
747
+ let currentInsight = null;
748
+
749
+ for (let i = 0; i < paragraphs.length; i++) {
750
+ if (paragraphs[i].trim()) {
751
+ // Check if this is a new insight section
752
+ if (paragraphs[i].toLowerCase().includes('insight') && paragraphs[i].includes(':')) {
753
+ // Create a new insight section
754
+ currentInsight = document.createElement('div');
755
+ currentInsight.className = 'insight-level';
756
+
757
+ const header = document.createElement('h4');
758
+ header.textContent = `Insight ${insightCounter}: ${paragraphs[i].split(':')[1].trim()}`;
759
+ currentInsight.appendChild(header);
760
+
761
+ outputEl.appendChild(currentInsight);
762
+ insightCounter++;
763
+ } else {
764
+ // Add paragraph to current insight or directly to output
765
+ const para = document.createElement('p');
766
+ para.textContent = paragraphs[i];
767
+ para.style.opacity = 0;
768
+ para.style.transform = 'translateY(10px)';
769
+ para.style.transition = 'opacity 0.5s, transform 0.5s';
770
+
771
+ if (currentInsight) {
772
+ currentInsight.appendChild(para);
773
+ } else {
774
+ outputEl.appendChild(para);
775
+ }
776
+
777
+ // Animate paragraph appearance
778
+ await new Promise(resolve => setTimeout(resolve, 300));
779
+ para.style.opacity = 1;
780
+ para.style.transform = 'translateY(0)';
781
+ }
782
+ }
783
+ }
784
+
785
+ // Update status
786
+ updateStatus(`Analysis of "${expression}" complete using ${config.modes[state.currentMode].name}`);
787
+ };
788
+
789
+ const generateTemplateBasedAnalysis = (expression) => {
790
+ // Template-based generation
791
+ let output = '';
792
+ const templates = config.llmlAnalysis[state.currentMode];
793
+
794
+ // Generate 3 insights
795
+ for (let i = 0; i < 3; i++) {
796
+ // Select template for insight level
797
+ const templateIndex = i % templates.length;
798
+ const template = templates[templateIndex];
799
+
800
+ // Add insight header
801
+ output += `Insight ${i+1}: ${state.currentMode.charAt(0).toUpperCase() + state.currentMode.slice(1)} Analysis\n\n`;
802
+
803
+ // Fill in template
804
+ let insight = template.replace('{expression}', expression);
805
+
806
+ // Add process
807
+ const processes = config.recursion.processes;
808
+ const process = processes[Math.floor(Math.random() * processes.length)];
809
+ insight = insight.replace('{process}', process);
810
+
811
+ // Add insight
812
+ const insights = config.recursion.insights;
813
+ const insightText = insights[Math.floor(Math.random() * insights.length)];
814
+ insight = insight.replace('{insight}', insightText);
815
+
816
+ // Add number
817
+ const number = Math.floor(Math.random() * 8) + 3; // 3-10
818
+ insight = insight.replace('{number}', number);
819
+
820
+ output += insight + '\n\n';
821
+ }
822
+
823
+ return output;
824
+ };
825
+
826
+ const updateStatus = (message) => {
827
+ statusEl.textContent = message;
828
+ statusEl.classList.add('pulsing');
829
+ setTimeout(() => {
830
+ statusEl.classList.remove('pulsing');
831
+ }, 1000);
832
+ };
833
+
834
+ const handleEvolve = async () => {
835
+ if (state.evolutionInProgress) return;
836
+
837
+ state.evolutionInProgress = true;
838
+ const depth = state.recursionDepth;
839
+
840
+ // Update status
841
+ updateStatus(`Initiating meta-recursive evolution cycle (depth: ${depth})...`);
842
+
843
+ // Notify other users if connected
844
+ if (state.multiplayer.connected) {
845
+ room.send({
846
+ type: 'evolution_triggered',
847
+ depth: depth,
848
+ username: state.multiplayer.username
849
+ });
850
+ }
851
+
852
+ // Calculate duration based on depth
853
+ const duration = config.evolution.baseDuration + (depth * config.evolution.depthMultiplier);
854
+
855
+ // Trigger evolution animation
856
+ visualizationEl.classList.add('evolving');
857
+
858
+ // Gradually improve metrics during evolution
859
+ const startMetrics = { ...state.metrics };
860
+ const targetMetrics = {
861
+ symbolic: Math.min(startMetrics.symbolic + (depth * 15), 100),
862
+ quantum: Math.min(startMetrics.quantum + (depth * 12), 100),
863
+ holographic: Math.min(startMetrics.holographic + (depth * 10), 100),
864
+ meta: Math.min(startMetrics.meta + (depth * 8), 100)
865
+ };
866
+
867
+ // Evolution steps
868
+ for (let i = 0; i < config.evolution.evolutionSteps.length; i++) {
869
+ const step = config.evolution.evolutionSteps[i];
870
+ updateStatus(`Evolution step ${i+1}/${config.evolution.evolutionSteps.length}: ${step}`);
871
+
872
+ // Update metrics proportionally for each step
873
+ const progress = (i + 1) / config.evolution.evolutionSteps.length;
874
+ state.metrics = {
875
+ symbolic: startMetrics.symbolic + (targetMetrics.symbolic - startMetrics.symbolic) * progress,
876
+ quantum: startMetrics.quantum + (targetMetrics.quantum - startMetrics.quantum) * progress,
877
+ holographic: startMetrics.holographic + (targetMetrics.holographic - startMetrics.holographic) * progress,
878
+ meta: startMetrics.meta + (targetMetrics.meta - startMetrics.meta) * progress
879
+ };
880
+
881
+ updateMetricsBars();
882
+
883
+ // Add visual effects during evolution
884
+ if (i === 0) {
885
+ // Symbolic embedding - SONW pattern briefly
886
+ createParticleSystem('sonw');
887
+ } else if (i === 1) {
888
+ // Quantum processing - Afterthought pattern briefly
889
+ createParticleSystem('afterthought');
890
+ } else if (i === 2) {
891
+ // Holographic integration - Holographic pattern briefly
892
+ createParticleSystem('cognitive');
893
+ } else if (i === 3) {
894
+ // Meta-evolution - Return to integrated pattern with improvements
895
+ createParticleSystem('integrated');
896
+ }
897
+
898
+ // Wait between steps
899
+ await new Promise(resolve => setTimeout(resolve, duration / config.evolution.evolutionSteps.length));
900
+ }
901
+
902
+ // Evolution complete
903
+ updateStatus(`Meta-recursive evolution complete (depth: ${depth})`);
904
+ visualizationEl.classList.remove('evolving');
905
+
906
+ // Return to original mode if not already in integrated
907
+ if (state.currentMode !== 'integrated') {
908
+ createParticleSystem(state.currentMode);
909
+ }
910
+
911
+ // Update room state with new metrics
912
+ if (state.multiplayer.connected) {
913
+ room.party.updateRoomState({
914
+ metrics: state.metrics
915
+ });
916
+ }
917
+
918
+ state.evolutionInProgress = false;
919
+ };
920
+
921
+ const handleModeChange = (mode) => {
922
+ if (state.evolutionInProgress) return;
923
+
924
+ state.currentMode = mode;
925
+
926
+ // Update active button
927
+ updateSystemButtonsUI();
928
+
929
+ // Update visualization
930
+ createParticleSystem(mode);
931
+
932
+ // Update status
933
+ updateStatus(`System switched to ${config.modes[mode].name}`);
934
+
935
+ // Update presence
936
+ if (state.multiplayer.connected) {
937
+ room.party.updatePresence({
938
+ mode: mode
939
+ });
940
+
941
+ // Send mode change event
942
+ room.send({
943
+ type: 'mode_change',
944
+ mode: mode,
945
+ username: state.multiplayer.username
946
+ });
947
+ }
948
+ };
949
+
950
+ const updateMetricsBars = () => {
951
+ document.getElementById('symbolicBar').style.width = `${state.metrics.symbolic}%`;
952
+ document.getElementById('quantumBar').style.width = `${state.metrics.quantum}%`;
953
+ document.getElementById('holoBar').style.width = `${state.metrics.holographic}%`;
954
+ document.getElementById('metaBar').style.width = `${state.metrics.meta}%`;
955
+ };
956
+
957
+ const initMultiplayer = async () => {
958
+ try {
959
+ // Get current user
960
+ state.multiplayer.userId = room.party.client.id;
961
+ state.multiplayer.username = room.party.client.username;
962
+
963
+ // Assign a color to the user
964
+ const colorIndex = Object.keys(room.party.peers).length % config.multiplayer.userColors.length;
965
+ state.multiplayer.userColor = config.multiplayer.userColors[colorIndex];
966
+
967
+ // Update presence with user info and initial state
968
+ room.party.updatePresence({
969
+ username: state.multiplayer.username,
970
+ color: state.multiplayer.userColor,
971
+ mode: state.currentMode,
972
+ cursorX: 0,
973
+ cursorY: 0,
974
+ isActive: true
975
+ });
976
+
977
+ // Subscribe to presence updates
978
+ room.party.subscribePresence(handlePresenceUpdates);
979
+
980
+ // Update room state with current system state if we're the first user
981
+ if (Object.keys(room.party.peers).length === 1) {
982
+ room.party.updateRoomState({
983
+ currentMode: state.currentMode,
984
+ metrics: state.metrics,
985
+ sharedAnalyses: []
986
+ });
987
+ }
988
+
989
+ // Subscribe to room state changes
990
+ room.party.subscribeRoomState(handleRoomStateChanges);
991
+
992
+ // Set up event listeners
993
+ room.onmessage = handleMessage;
994
+
995
+ // Set up mouse move for cursor sharing
996
+ visualizationEl.addEventListener('mousemove', handleMouseMove);
997
+
998
+ // Set up touch move for mobile
999
+ visualizationEl.addEventListener('touchmove', handleTouchMove);
1000
+
1001
+ state.multiplayer.connected = true;
1002
+ showNotification(`Connected as ${state.multiplayer.username}`);
1003
+
1004
+ } catch (error) {
1005
+ console.error('Error initializing multiplayer:', error);
1006
+ showNotification('Failed to connect to multiplayer session');
1007
+ }
1008
+ };
1009
+
1010
+ const handlePresenceUpdates = (presence) => {
1011
+ // Update local state with researchers
1012
+ state.multiplayer.researchers = presence;
1013
+
1014
+ // Update UI
1015
+ updateResearchersUI();
1016
+ updateUserCursors();
1017
+
1018
+ // Update user count
1019
+ const userCount = Object.keys(presence).length;
1020
+ userCountEl.textContent = userCount;
1021
+ };
1022
+
1023
+ const handleRoomStateChanges = (roomState) => {
1024
+ // Check if room state is defined
1025
+ if (!roomState) return;
1026
+
1027
+ // Update mode if changed by another user
1028
+ if (roomState.currentMode && roomState.currentMode !== state.currentMode) {
1029
+ state.currentMode = roomState.currentMode;
1030
+ updateSystemButtonsUI();
1031
+ createParticleSystem(state.currentMode);
1032
+ }
1033
+
1034
+ // Update metrics if changed
1035
+ if (roomState.metrics) {
1036
+ state.metrics = roomState.metrics;
1037
+ updateMetricsBars();
1038
+ }
1039
+
1040
+ // Update shared analyses if changed
1041
+ if (roomState.sharedAnalyses) {
1042
+ state.multiplayer.sharedAnalyses = roomState.sharedAnalyses;
1043
+ updateSharedAnalysesUI();
1044
+ }
1045
+ };
1046
+
1047
+ const handleMessage = (event) => {
1048
+ const data = event.data;
1049
+
1050
+ switch (data.type) {
1051
+ case 'connected':
1052
+ showNotification(`${data.username} connected`);
1053
+ break;
1054
+
1055
+ case 'disconnected':
1056
+ showNotification(`${data.username} disconnected`);
1057
+ break;
1058
+
1059
+ case 'mode_change':
1060
+ if (data.clientId !== state.multiplayer.userId) {
1061
+ showNotification(`${data.username} switched mode to ${config.modes[data.mode].name}`);
1062
+ }
1063
+ break;
1064
+
1065
+ case 'analysis_shared':
1066
+ if (data.clientId !== state.multiplayer.userId) {
1067
+ showNotification(`${data.username} shared an analysis of "${data.expression}"`);
1068
+ }
1069
+ break;
1070
+
1071
+ case 'evolution_triggered':
1072
+ if (data.clientId !== state.multiplayer.userId) {
1073
+ showNotification(`${data.username} triggered evolution (depth: ${data.depth})`);
1074
+ }
1075
+ break;
1076
+ }
1077
+ };
1078
+
1079
+ const updateResearchersUI = () => {
1080
+ researchersEl.innerHTML = '';
1081
+
1082
+ for (const userId in state.multiplayer.researchers) {
1083
+ const researcher = state.multiplayer.researchers[userId];
1084
+ if (!researcher.username || !researcher.isActive) continue;
1085
+
1086
+ const researcherEl = document.createElement('div');
1087
+ researcherEl.className = 'researcher';
1088
+
1089
+ const colorEl = document.createElement('div');
1090
+ colorEl.className = 'researcher-color';
1091
+ colorEl.style.backgroundColor = researcher.color;
1092
+
1093
+ const nameEl = document.createElement('div');
1094
+ nameEl.className = 'researcher-name';
1095
+ nameEl.textContent = researcher.username;
1096
+
1097
+ researcherEl.appendChild(colorEl);
1098
+ researcherEl.appendChild(nameEl);
1099
+ researchersEl.appendChild(researcherEl);
1100
+ }
1101
+ };
1102
+
1103
+ const updateUserCursors = () => {
1104
+ userCursorsEl.innerHTML = '';
1105
+
1106
+ for (const userId in state.multiplayer.researchers) {
1107
+ // Skip own cursor
1108
+ if (userId === state.multiplayer.userId) continue;
1109
+
1110
+ const researcher = state.multiplayer.researchers[userId];
1111
+ if (!researcher.isActive) continue;
1112
+
1113
+ const cursorEl = document.createElement('div');
1114
+ cursorEl.className = 'user-cursor';
1115
+ cursorEl.style.backgroundColor = researcher.color;
1116
+ cursorEl.style.left = `${researcher.cursorX}px`;
1117
+ cursorEl.style.top = `${researcher.cursorY}px`;
1118
+
1119
+ // Add username label
1120
+ const labelEl = document.createElement('div');
1121
+ labelEl.style.position = 'absolute';
1122
+ labelEl.style.top = '20px';
1123
+ labelEl.style.left = '10px';
1124
+ labelEl.style.fontSize = '12px';
1125
+ labelEl.style.whiteSpace = 'nowrap';
1126
+ labelEl.textContent = researcher.username;
1127
+
1128
+ cursorEl.appendChild(labelEl);
1129
+ userCursorsEl.appendChild(cursorEl);
1130
+ }
1131
+ };
1132
+
1133
+ const handleMouseMove = (event) => {
1134
+ if (!state.multiplayer.connected) return;
1135
+
1136
+ // Get cursor position relative to visualization element
1137
+ const rect = visualizationEl.getBoundingClientRect();
1138
+ const x = event.clientX - rect.left;
1139
+ const y = event.clientY - rect.top;
1140
+
1141
+ // Update presence with cursor position
1142
+ room.party.updatePresence({
1143
+ cursorX: x,
1144
+ cursorY: y
1145
+ });
1146
+ };
1147
+
1148
+ const handleTouchMove = (event) => {
1149
+ if (!state.multiplayer.connected || !event.touches[0]) return;
1150
+
1151
+ // Get touch position relative to visualization element
1152
+ const rect = visualizationEl.getBoundingClientRect();
1153
+ const x = event.touches[0].clientX - rect.left;
1154
+ const y = event.touches[0].clientY - rect.top;
1155
+
1156
+ // Update presence with cursor position
1157
+ room.party.updatePresence({
1158
+ cursorX: x,
1159
+ cursorY: y
1160
+ });
1161
+ };
1162
+
1163
+ const shareAnalysis = () => {
1164
+ if (!state.multiplayer.connected) return;
1165
+
1166
+ // Get current output content
1167
+ const outputContent = outputEl.innerText;
1168
+
1169
+ // Check if there's content to share
1170
+ if (!outputContent || outputContent.includes('placeholder')) {
1171
+ showNotification('Nothing to share. Process an expression first.');
1172
+ return;
1173
+ }
1174
+
1175
+ // Get the current expression
1176
+ let expression = conceptInput.value.trim();
1177
+
1178
+ if (!expression) {
1179
+ // Use selected expression from dropdown
1180
+ const selectedKey = symbolSelector.value;
1181
+ expression = config.symbolicExpressions[selectedKey].expression;
1182
+ }
1183
+
1184
+ // Create shared analysis
1185
+ const sharedAnalysis = {
1186
+ id: Date.now().toString(),
1187
+ username: state.multiplayer.username,
1188
+ userId: state.multiplayer.userId,
1189
+ color: state.multiplayer.userColor,
1190
+ timestamp: new Date().toISOString(),
1191
+ expression,
1192
+ content: outputContent.substring(0, config.multiplayer.sharingSettings.characterLimit),
1193
+ mode: state.currentMode
1194
+ };
1195
+
1196
+ // Get current shared analyses
1197
+ const sharedAnalyses = [...state.multiplayer.sharedAnalyses];
1198
+
1199
+ // Add new analysis
1200
+ sharedAnalyses.push(sharedAnalysis);
1201
+
1202
+ // Limit number of shared analyses
1203
+ if (sharedAnalyses.length > config.multiplayer.sharingSettings.maxSharedAnalyses) {
1204
+ sharedAnalyses.shift();
1205
+ }
1206
+
1207
+ // Update room state
1208
+ room.party.updateRoomState({
1209
+ sharedAnalyses
1210
+ });
1211
+
1212
+ // Send notification to other users
1213
+ room.send({
1214
+ type: 'analysis_shared',
1215
+ expression,
1216
+ username: state.multiplayer.username
1217
+ });
1218
+
1219
+ showNotification('Analysis shared with all researchers');
1220
+ };
1221
+
1222
+ const syncVisualization = () => {
1223
+ if (!state.multiplayer.connected) return;
1224
+
1225
+ // Update room state with current state
1226
+ room.party.updateRoomState({
1227
+ currentMode: state.currentMode,
1228
+ metrics: state.metrics
1229
+ });
1230
+
1231
+ showNotification('Visualization synchronized with all researchers');
1232
+ };
1233
+
1234
+ const updateSharedAnalysesUI = () => {
1235
+ sharedAnalysesListEl.innerHTML = '';
1236
+
1237
+ if (state.multiplayer.sharedAnalyses.length === 0) {
1238
+ sharedAnalysesListEl.innerHTML = '<p class="placeholder">No shared analyses yet.</p>';
1239
+ return;
1240
+ }
1241
+
1242
+ // Sort analyses by timestamp (newest first)
1243
+ const sortedAnalyses = [...state.multiplayer.sharedAnalyses].sort((a, b) =>
1244
+ new Date(b.timestamp) - new Date(a.timestamp)
1245
+ );
1246
+
1247
+ for (const analysis of sortedAnalyses) {
1248
+ const analysisEl = document.createElement('div');
1249
+ analysisEl.className = 'shared-analysis';
1250
+
1251
+ const headerEl = document.createElement('div');
1252
+ headerEl.className = 'shared-header';
1253
+
1254
+ const userEl = document.createElement('span');
1255
+ userEl.style.color = analysis.color;
1256
+ userEl.textContent = analysis.username;
1257
+
1258
+ const timeEl = document.createElement('span');
1259
+ timeEl.textContent = formatTimestamp(analysis.timestamp);
1260
+
1261
+ headerEl.appendChild(userEl);
1262
+ headerEl.appendChild(timeEl);
1263
+
1264
+ const expressionEl = document.createElement('div');
1265
+ expressionEl.className = 'shared-expression';
1266
+ expressionEl.textContent = `"${analysis.expression}"`;
1267
+
1268
+ const contentEl = document.createElement('div');
1269
+ contentEl.className = 'shared-content';
1270
+ contentEl.innerHTML = analysis.content;
1271
+
1272
+ analysisEl.appendChild(headerEl);
1273
+ analysisEl.appendChild(expressionEl);
1274
+ analysisEl.appendChild(contentEl);
1275
+
1276
+ sharedAnalysesListEl.appendChild(analysisEl);
1277
+ }
1278
+ };
1279
+
1280
+ const formatTimestamp = (timestamp) => {
1281
+ const date = new Date(timestamp);
1282
+ return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
1283
+ };
1284
+
1285
+ const showNotification = (message) => {
1286
+ notificationEl.textContent = message;
1287
+ notificationEl.classList.add('show');
1288
+
1289
+ setTimeout(() => {
1290
+ notificationEl.classList.remove('show');
1291
+ }, config.multiplayer.notificationDuration);
1292
+ };
1293
+
1294
+ const updateSystemButtonsUI = () => {
1295
+ systemButtons.forEach(btn => {
1296
+ btn.classList.remove('active');
1297
+ if (btn.id === `${state.currentMode}Btn`) {
1298
+ btn.classList.add('active');
1299
+ }
1300
+ });
1301
+ };
1302
+
1303
+ // Event listeners
1304
+ window.addEventListener('DOMContentLoaded', () => {
1305
+ // Initialize visualization
1306
+ initVisualization();
1307
+
1308
+ // Initialize metrics display
1309
+ updateMetricsBars();
1310
+
1311
+ // Initialize multiplayer
1312
+ initMultiplayer();
1313
+
1314
+ // Mode buttons
1315
+ document.getElementById('sonwBtn').addEventListener('click', () => handleModeChange('sonw'));
1316
+ document.getElementById('afterthoughtBtn').addEventListener('click', () => handleModeChange('afterthought'));
1317
+ document.getElementById('cognitiveBtn').addEventListener('click', () => handleModeChange('cognitive'));
1318
+ document.getElementById('integratedBtn').addEventListener('click', () => handleModeChange('integrated'));
1319
+
1320
+ // Recursion depth slider
1321
+ depthSlider.addEventListener('input', () => {
1322
+ state.recursionDepth = parseInt(depthSlider.value);
1323
+ depthValueEl.textContent = depthSlider.value;
1324
+ });
1325
+
1326
+ // Evolution button
1327
+ document.getElementById('evolveBtn').addEventListener('click', handleEvolve);
1328
+
1329
+ // Symbolic expression selector
1330
+ symbolSelector.addEventListener('change', () => {
1331
+ const selectedKey = symbolSelector.value;
1332
+ const selectedExpression = config.symbolicExpressions[selectedKey];
1333
+ conceptInput.placeholder = selectedExpression.expression;
1334
+
1335
+ // Display preview
1336
+ outputEl.innerHTML = `
1337
+ <p><strong>${selectedExpression.description}</strong></p>
1338
+ <p class="symbolic-node">${selectedExpression.expression}</p>
1339
+ <ul>
1340
+ ${selectedExpression.components.map(comp => `<li>${comp}</li>`).join('')}
1341
+ </ul>
1342
+ <p class="placeholder">Press "Process" to analyze this expression...</p>
1343
+ `;
1344
+ });
1345
+
1346
+ // Process symbolic expression
1347
+ document.getElementById('processBtn').addEventListener('click', handleSymbolicProcess);
1348
+ conceptInput.addEventListener('keypress', (e) => {
1349
+ if (e.key === 'Enter') {
1350
+ handleSymbolicProcess();
1351
+ }
1352
+ });
1353
+
1354
+ // Collaborative features
1355
+ shareBtn.addEventListener('click', shareAnalysis);
1356
+ syncBtn.addEventListener('click', syncVisualization);
1357
+
1358
+ // Handle window unload to update presence
1359
+ window.addEventListener('beforeunload', () => {
1360
+ if (state.multiplayer.connected) {
1361
+ room.party.updatePresence({
1362
+ isActive: false
1363
+ });
1364
+ }
1365
+ });
1366
+ });