TheGreatUnknown's picture
Rename script.js to scripts.js
ff0ff96 verified
import { config } from './config.js';
import * as THREE from 'three';
import { OrbitControls } from 'three/addons/controls/OrbitControls.js';
// Main application state
const state = {
currentMode: 'sonw',
evolutionInProgress: false,
recursionDepth: 3,
particles: [],
metrics: {
symbolic: 20,
quantum: 15,
holographic: 10,
meta: 5
},
// Multiplayer state
multiplayer: {
connected: false,
username: '',
userId: '',
userColor: '',
researchers: {},
sharedAnalyses: []
}
};
// Initialize WebsimSocket for multiplayer
const room = new WebsimSocket();
// DOM elements
const visualizationEl = document.getElementById('visualization');
const conceptInput = document.getElementById('conceptInput');
const symbolSelector = document.getElementById('symbolSelector');
const outputEl = document.getElementById('output');
const statusEl = document.getElementById('statusDisplay');
const depthSlider = document.getElementById('recursionDepth');
const depthValueEl = document.getElementById('depthValue');
const systemButtons = ['sonwBtn', 'afterthoughtBtn', 'cognitiveBtn', 'integratedBtn'].map(id => document.getElementById(id));
const userCountEl = document.getElementById('user-count');
const researchersEl = document.getElementById('researchers');
const shareBtn = document.getElementById('shareBtn');
const syncBtn = document.getElementById('syncBtn');
const sharedAnalysesListEl = document.getElementById('shared-analyses-list');
const userCursorsEl = document.getElementById('user-cursors');
const notificationEl = document.getElementById('notification');
// Three.js setup
let scene, camera, renderer, controls;
let particles, connections;
const initVisualization = () => {
// Setup Three.js scene
scene = new THREE.Scene();
scene.background = new THREE.Color(config.visualization.backgroundColor);
// Setup camera
camera = new THREE.PerspectiveCamera(75, visualizationEl.clientWidth / visualizationEl.clientHeight, 0.1, 2000);
camera.position.z = 300;
// Setup renderer
renderer = new THREE.WebGLRenderer({ antialias: true });
renderer.setSize(visualizationEl.clientWidth, visualizationEl.clientHeight);
visualizationEl.appendChild(renderer.domElement);
// Add orbit controls
controls = new OrbitControls(camera, renderer.domElement);
controls.enableDamping = true;
controls.dampingFactor = 0.05;
// Create particles group
particles = new THREE.Group();
scene.add(particles);
// Create connections group
connections = new THREE.Group();
scene.add(connections);
// Add grid for reference
const gridHelper = new THREE.GridHelper(400, 20, 0x404040, 0x404040);
gridHelper.position.y = -100;
scene.add(gridHelper);
// Add ambient light
const ambientLight = new THREE.AmbientLight(0xffffff, 0.5);
scene.add(ambientLight);
// Add point light
const pointLight = new THREE.PointLight(0xffffff, 1);
pointLight.position.set(0, 150, 200);
scene.add(pointLight);
// Initialize particles based on current mode
createParticleSystem(state.currentMode);
// Start animation loop
animate();
// Handle window resize
window.addEventListener('resize', onWindowResize);
};
const onWindowResize = () => {
camera.aspect = visualizationEl.clientWidth / visualizationEl.clientHeight;
camera.updateProjectionMatrix();
renderer.setSize(visualizationEl.clientWidth, visualizationEl.clientHeight);
};
const createFractalNetworkPattern = (geometry, material, modeConfig) => {
// Create network-like distribution with fractal properties
for (let i = 0; i < config.visualization.particleCount; i++) {
const particle = new THREE.Mesh(geometry, material);
// Position in fractal network structure
const fractalDepth = Math.floor(Math.random() * 3) + 1;
const angleXY = Math.random() * Math.PI * 2;
const radiusXY = 20 + Math.random() * modeConfig.particleSpread * 0.5;
// Use fractal positioning algorithm
const fractalScale = 1 / (fractalDepth * 0.5);
particle.position.x = Math.cos(angleXY) * radiusXY * fractalScale;
particle.position.y = (fractalDepth * 40) - 60;
particle.position.z = Math.sin(angleXY) * radiusXY * fractalScale;
// Add controlled fractal variation
particle.position.x += (Math.random() - 0.5) * 40 * fractalScale;
particle.position.z += (Math.random() - 0.5) * 40 * fractalScale;
// Store velocity and fractal properties for animation
particle.userData = {
velocity: new THREE.Vector3(
(Math.random() - 0.5) * 0.2 * fractalScale,
(Math.random() - 0.5) * 0.1 * fractalScale,
(Math.random() - 0.5) * 0.2 * fractalScale
),
originalPosition: particle.position.clone(),
fractalDepth: fractalDepth
};
particles.add(particle);
state.particles.push(particle);
}
};
const createQuantumFieldPattern = (geometry, material, modeConfig) => {
// Create quantum field-like distribution
for (let i = 0; i < config.visualization.particleCount; i++) {
const particle = new THREE.Mesh(geometry, material);
// Position in a spherical field with superposition properties
const phi = Math.acos(-1 + 2 * Math.random());
const theta = 2 * Math.PI * Math.random();
const radius = 50 + Math.random() * modeConfig.particleSpread * 0.6;
particle.position.x = radius * Math.sin(phi) * Math.cos(theta);
particle.position.y = radius * Math.sin(phi) * Math.sin(theta);
particle.position.z = radius * Math.cos(phi);
// Quantum properties for animation
const superposition = Math.random() > 0.5;
const entanglementFactor = Math.random();
const orbitalAxis = new THREE.Vector3(
Math.random() - 0.5,
Math.random() - 0.5,
Math.random() - 0.5
).normalize();
particle.userData = {
velocity: new THREE.Vector3(
(Math.random() - 0.5) * 0.1,
(Math.random() - 0.5) * 0.1,
(Math.random() - 0.5) * 0.1
),
originalPosition: particle.position.clone(),
superposition: superposition,
entanglementFactor: entanglementFactor,
orbitalAxis: orbitalAxis,
orbitalSpeed: (Math.random() * 0.01) + 0.005
};
particles.add(particle);
state.particles.push(particle);
}
};
const createFractalPattern = (geometry, material, modeConfig) => {
// Create fractal-like distribution for Holographic Intelligence
// Use recursive patterns with self-similarity
const createFractalPoint = (centerPoint, scale, depth) => {
if (depth <= 0 || state.particles.length >= config.visualization.particleCount) return;
// Create center particle
const particle = new THREE.Mesh(geometry, material);
particle.position.copy(centerPoint);
// Add some variation
particle.position.x += (Math.random() - 0.5) * scale * 0.2;
particle.position.y += (Math.random() - 0.5) * scale * 0.2;
particle.position.z += (Math.random() - 0.5) * scale * 0.2;
particle.userData = {
velocity: new THREE.Vector3(
(Math.random() - 0.5) * 0.1,
(Math.random() - 0.5) * 0.1,
(Math.random() - 0.5) * 0.1
),
originalPosition: particle.position.clone(),
fractalDepth: depth
};
particles.add(particle);
state.particles.push(particle);
// Create sub-structures (branches)
const branchCount = 6;
const newScale = scale * 0.6;
for (let i = 0; i < branchCount; i++) {
// Create points in a geodesic-like pattern
const angle1 = (i / branchCount) * Math.PI * 2;
const angle2 = Math.PI / 4; // Fixed angle from center
const newX = centerPoint.x + Math.sin(angle1) * Math.cos(angle2) * scale;
const newY = centerPoint.y + Math.sin(angle1) * Math.sin(angle2) * scale;
const newZ = centerPoint.z + Math.cos(angle1) * scale;
const newPoint = new THREE.Vector3(newX, newY, newZ);
// Recursive call for each branch
createFractalPoint(newPoint, newScale, depth - 1);
}
};
// Start the recursive fractal generation from center
createFractalPoint(new THREE.Vector3(0, 0, 0), modeConfig.particleSpread * 0.3, 3);
};
const createHolisticPattern = (geometry, material, modeConfig) => {
// Create an integrated pattern combining aspects of all systems
// First layer: LLML networked structure (30% of particles)
const llmlCount = Math.floor(config.visualization.particleCount * 0.3);
for (let i = 0; i < llmlCount; i++) {
const particle = new THREE.Mesh(geometry, material);
// Layered network structure
const layerIndex = Math.floor(Math.random() * 3);
const angleXY = Math.random() * Math.PI * 2;
const radiusXY = 30 + Math.random() * 60;
particle.position.x = Math.cos(angleXY) * radiusXY;
particle.position.y = (layerIndex * 40) - 40;
particle.position.z = Math.sin(angleXY) * radiusXY;
particle.userData = {
velocity: new THREE.Vector3(
(Math.random() - 0.5) * 0.15,
(Math.random() - 0.5) * 0.05,
(Math.random() - 0.5) * 0.15
),
originalPosition: particle.position.clone(),
system: 'llml'
};
particles.add(particle);
state.particles.push(particle);
}
// Second layer: QGA quantum field (30% of particles)
const qgaCount = Math.floor(config.visualization.particleCount * 0.3);
for (let i = 0; i < qgaCount; i++) {
const particle = new THREE.Mesh(geometry, material);
// Spherical field distribution
const phi = Math.acos(-1 + 2 * Math.random());
const theta = 2 * Math.PI * Math.random();
const radius = 80 + Math.random() * 70;
particle.position.x = radius * Math.sin(phi) * Math.cos(theta);
particle.position.y = radius * Math.sin(phi) * Math.sin(theta);
particle.position.z = radius * Math.cos(phi);
const orbitalAxis = new THREE.Vector3(
Math.random() - 0.5,
Math.random() - 0.5,
Math.random() - 0.5
).normalize();
particle.userData = {
velocity: new THREE.Vector3(
(Math.random() - 0.5) * 0.1,
(Math.random() - 0.5) * 0.1,
(Math.random() - 0.5) * 0.1
),
originalPosition: particle.position.clone(),
orbitalAxis: orbitalAxis,
orbitalSpeed: (Math.random() * 0.01) + 0.005,
system: 'qga'
};
particles.add(particle);
state.particles.push(particle);
}
// Third layer: Holographic fractal points (remaining particles)
const holoCount = config.visualization.particleCount - llmlCount - qgaCount;
// Generate a few fractal seed points
for (let i = 0; i < 5; i++) {
const centerPoint = new THREE.Vector3(
(Math.random() - 0.5) * 150,
(Math.random() - 0.5) * 150,
(Math.random() - 0.5) * 150
);
// Create mini fractal clusters
for (let j = 0; j < holoCount / 5; j++) {
const particle = new THREE.Mesh(geometry, material);
// Position in a cluster around the center point
const fractalRadius = 10 + Math.random() * 25;
const fractalPhi = Math.acos(-1 + 2 * Math.random());
const fractalTheta = 2 * Math.PI * Math.random();
particle.position.x = centerPoint.x + fractalRadius * Math.sin(fractalPhi) * Math.cos(fractalTheta);
particle.position.y = centerPoint.y + fractalRadius * Math.sin(fractalPhi) * Math.sin(fractalTheta);
particle.position.z = centerPoint.z + fractalRadius * Math.cos(fractalPhi);
particle.userData = {
velocity: new THREE.Vector3(
(Math.random() - 0.5) * 0.1,
(Math.random() - 0.5) * 0.1,
(Math.random() - 0.5) * 0.1
),
originalPosition: particle.position.clone(),
fractalCenter: centerPoint.clone(),
system: 'holographic'
};
particles.add(particle);
state.particles.push(particle);
}
}
};
const createConnections = (modeConfig) => {
// Create connections between particles based on proximity
const linesMaterial = new THREE.LineBasicMaterial({
color: config.visualization.connectionColor,
transparent: true,
opacity: 0.3
});
const particlePositions = state.particles.map(p => p.position);
const threshold = config.visualization.connectionThreshold * modeConfig.connectionDensity;
for (let i = 0; i < particlePositions.length; i++) {
for (let j = i + 1; j < particlePositions.length; j++) {
const distance = particlePositions[i].distanceTo(particlePositions[j]);
if (distance < threshold) {
// Create connection between these particles
const lineGeometry = new THREE.BufferGeometry().setFromPoints([
particlePositions[i],
particlePositions[j]
]);
const line = new THREE.Line(lineGeometry, linesMaterial);
connections.add(line);
// Link the connection to particles
line.userData = {
particleIndexA: i,
particleIndexB: j
};
}
}
}
};
const updateConnections = () => {
// Update all connection lines to match particle positions
connections.children.forEach(line => {
const { particleIndexA, particleIndexB } = line.userData;
if (particleIndexA < state.particles.length && particleIndexB < state.particles.length) {
const posA = state.particles[particleIndexA].position;
const posB = state.particles[particleIndexB].position;
const positions = line.geometry.attributes.position.array;
// Update positions
positions[0] = posA.x;
positions[1] = posA.y;
positions[2] = posA.z;
positions[3] = posB.x;
positions[4] = posB.y;
positions[5] = posB.z;
line.geometry.attributes.position.needsUpdate = true;
}
});
};
const animate = () => {
requestAnimationFrame(animate);
// Animate particles based on mode
animateParticles();
// Update connections
updateConnections();
// Update orbital controls
controls.update();
// Render scene
renderer.render(scene, camera);
};
const animateParticles = () => {
// Apply different animation based on current mode
const mode = state.currentMode;
switch(mode) {
case 'sonw':
// Network-like movement
animateSONWParticles();
break;
case 'afterthought':
// Quantum field movement
animateQGAParticles();
break;
case 'cognitive':
// Fractal pattern movement
animateHolographicParticles();
break;
case 'integrated':
// Combined animation of all systems
animateIntegratedParticles();
break;
}
};
const animateSONWParticles = () => {
state.particles.forEach(particle => {
// Gentle oscillation around original position
const origPos = particle.userData.originalPosition;
const velocity = particle.userData.velocity;
// Move with velocity
particle.position.x += velocity.x;
particle.position.y += velocity.y;
particle.position.z += velocity.z;
// Apply a force back toward original position
const diffX = origPos.x - particle.position.x;
const diffY = origPos.y - particle.position.y;
const diffZ = origPos.z - particle.position.z;
velocity.x += diffX * 0.01;
velocity.y += diffY * 0.01;
velocity.z += diffZ * 0.01;
// Dampen velocity
velocity.x *= 0.98;
velocity.y *= 0.98;
velocity.z *= 0.98;
});
};
const animateQGAParticles = () => {
state.particles.forEach(particle => {
// Quantum-inspired orbital movement
const velocity = particle.userData.velocity;
const orbitalAxis = particle.userData.orbitalAxis;
const orbitalSpeed = particle.userData.orbitalSpeed;
// Apply orbital rotation
const rotationMatrix = new THREE.Matrix4().makeRotationAxis(orbitalAxis, orbitalSpeed);
particle.position.applyMatrix4(rotationMatrix);
// Add some random quantum fluctuation
velocity.x += (Math.random() - 0.5) * 0.02;
velocity.y += (Math.random() - 0.5) * 0.02;
velocity.z += (Math.random() - 0.5) * 0.02;
// Apply velocity with strong damping (quantum fluctuations don't accumulate)
particle.position.x += velocity.x;
particle.position.y += velocity.y;
particle.position.z += velocity.z;
// Strong damping for stability
velocity.x *= 0.8;
velocity.y *= 0.8;
velocity.z *= 0.8;
});
};
const animateHolographicParticles = () => {
state.particles.forEach(particle => {
// Fractal pulsing movement
const velocity = particle.userData.velocity;
const fractalDepth = particle.userData.fractalDepth || 1;
// Deeper fractal levels move less
const depthFactor = 1 / (fractalDepth * 0.5);
// Apply a pulsing movement
const time = Date.now() * 0.001;
const pulseFactor = Math.sin(time * 0.5) * 0.2 * depthFactor;
// Move with velocity and pulse
particle.position.x += velocity.x + (particle.position.x * pulseFactor);
particle.position.y += velocity.y + (particle.position.y * pulseFactor);
particle.position.z += velocity.z + (particle.position.z * pulseFactor);
// Apply a centering force to maintain overall structure
const centeringForce = 0.001 * depthFactor;
velocity.x -= particle.position.x * centeringForce;
velocity.y -= particle.position.y * centeringForce;
velocity.z -= particle.position.z * centeringForce;
// Dampen velocity
velocity.x *= 0.95;
velocity.y *= 0.95;
velocity.z *= 0.95;
});
};
const animateIntegratedParticles = () => {
state.particles.forEach(particle => {
// Apply animation based on the particle's system
const system = particle.userData.system;
if (system === 'llml') {
// Network node behavior
const origPos = particle.userData.originalPosition;
const velocity = particle.userData.velocity;
particle.position.x += velocity.x;
particle.position.y += velocity.y;
particle.position.z += velocity.z;
const diffX = origPos.x - particle.position.x;
const diffY = origPos.y - particle.position.y;
const diffZ = origPos.z - particle.position.z;
velocity.x += diffX * 0.01;
velocity.y += diffY * 0.01;
velocity.z += diffZ * 0.01;
velocity.x *= 0.98;
velocity.y *= 0.98;
velocity.z *= 0.98;
} else if (system === 'qga') {
// Quantum field behavior
const velocity = particle.userData.velocity;
const orbitalAxis = particle.userData.orbitalAxis;
const orbitalSpeed = particle.userData.orbitalSpeed;
const rotationMatrix = new THREE.Matrix4().makeRotationAxis(orbitalAxis, orbitalSpeed);
particle.position.applyMatrix4(rotationMatrix);
velocity.x += (Math.random() - 0.5) * 0.02;
velocity.y += (Math.random() - 0.5) * 0.02;
velocity.z += (Math.random() - 0.5) * 0.02;
particle.position.x += velocity.x;
particle.position.y += velocity.y;
particle.position.z += velocity.z;
velocity.x *= 0.8;
velocity.y *= 0.8;
velocity.z *= 0.8;
} else if (system === 'holographic') {
// Fractal behavior
const velocity = particle.userData.velocity;
const fractalCenter = particle.userData.fractalCenter;
// Pulsing movement
const time = Date.now() * 0.001;
const pulseFactor = Math.sin(time * 0.5) * 0.2;
// Vector from fractal center to particle
const dirX = particle.position.x - fractalCenter.x;
const dirY = particle.position.y - fractalCenter.y;
const dirZ = particle.position.z - fractalCenter.z;
// Apply pulse along this direction
particle.position.x += velocity.x + (dirX * pulseFactor * 0.01);
particle.position.y += velocity.y + (dirY * pulseFactor * 0.01);
particle.position.z += velocity.z + (dirZ * pulseFactor * 0.01);
// Apply a centering force to maintain cluster
const centeringForce = 0.001;
velocity.x -= dirX * centeringForce;
velocity.y -= dirY * centeringForce;
velocity.z -= dirZ * centeringForce;
velocity.x *= 0.95;
velocity.y *= 0.95;
velocity.z *= 0.95;
}
});
// Add emergent behavior for the integrated system
// This creates interactions between the different systems
// Slow rotation of the entire system
particles.rotation.y += 0.0005;
connections.rotation.y += 0.0005;
};
const createParticleSystem = (mode) => {
// Clear existing particles and connections
while(particles.children.length > 0) {
particles.remove(particles.children[0]);
}
while(connections.children.length > 0) {
connections.remove(connections.children[0]);
}
// Get mode configuration
const modeConfig = config.modes[mode];
// Create particles
const particleGeometry = new THREE.SphereGeometry(config.visualization.nodeSize, 16, 16);
const particleMaterial = new THREE.MeshPhongMaterial({
color: new THREE.Color(modeConfig.color),
emissive: new THREE.Color(modeConfig.color).multiplyScalar(0.5),
shininess: 50
});
// Create particles based on pattern type
state.particles = [];
switch(modeConfig.patternType) {
case 'fractal-network':
// Create fractal-network pattern (SONW)
createFractalNetworkPattern(particleGeometry, particleMaterial, modeConfig);
break;
case 'quantum-field':
// Create quantum field pattern (Afterthought)
createQuantumFieldPattern(particleGeometry, particleMaterial, modeConfig);
break;
case 'holographic':
// Create holographic pattern (Cognitive)
createFractalPattern(particleGeometry, particleMaterial, modeConfig);
break;
case 'holistic':
// Create holistic pattern (Integrated)
createHolisticPattern(particleGeometry, particleMaterial, modeConfig);
break;
}
// Create connections between particles
createConnections(modeConfig);
};
const handleSymbolicProcess = async () => {
if (state.evolutionInProgress) return;
// Get symbolic expression from input or selector
let symbolicExpression = conceptInput.value.trim();
if (!symbolicExpression) {
// Use selected expression from dropdown
const selectedKey = symbolSelector.value;
symbolicExpression = config.symbolicExpressions[selectedKey].expression;
}
// Start processing animation
updateStatus(`Processing symbolic expression: ${symbolicExpression}`);
outputEl.innerHTML = `<p>Analyzing ${symbolicExpression}...</p>`;
visualizationEl.classList.add('recursing');
// Simulate processing with the current system
await new Promise(resolve => setTimeout(resolve, 1500));
// Generate analysis
await generateSymbolicAnalysis(symbolicExpression);
// End animation
visualizationEl.classList.remove('recursing');
};
const generateSymbolicAnalysis = async (expression) => {
// Using the LLM to generate a better response
let analysisOutput = '';
try {
// Prepare prompt for LLM
const systemPrompt = `You are the Meta-Cosmic-Weaver, an advanced AI that integrates SONW (Symbolicentric Orbital Neural Weave),
Afterthought Quantum Conceptualization, and Cognitive Engine components into a Triadic Architecture for recursive intelligence.
Analyze the symbolic LLML expression provided and generate 3 insights corresponding to these three levels:
Insight 1 (SONW): Analyze the expression as a fractal-symbolic framework using algebraic reasoning structures and neural-symbolic integration.
Insight 2 (Afterthought): Provide a quantum-inspired interpretation that explores superposition, entanglement, and probabilistic consciousness.
Insight 3 (Cognitive): Offer a meta-mathematical interpretation that treats the expression as an executable semantic transformation protocol.
Use terminology from: quantum mechanics, geometric algebra, fractal mathematics, neural-symbolic integration, and recursive symbolic systems.
Each insight should build upon the previous one with increasing sophistication.`;
const messages = [
{
role: "system",
content: systemPrompt
},
{
role: "user",
content: `Generate three progressive insights for the LLML symbolic expression: ${expression}`
}
];
// Generate response using LLM
const completion = await websim.chat.completions.create({
messages: messages
});
analysisOutput = completion.content;
} catch (error) {
// Fallback to template-based generation
console.log("Using template-based generation instead of LLM");
analysisOutput = generateTemplateBasedAnalysis(expression);
}
// Display output with animation
outputEl.innerHTML = ''; // Clear output
// Split by paragraphs and display with delay
const paragraphs = analysisOutput.split('\n\n');
let insightCounter = 1;
let currentInsight = null;
for (let i = 0; i < paragraphs.length; i++) {
if (paragraphs[i].trim()) {
// Check if this is a new insight section
if (paragraphs[i].toLowerCase().includes('insight') && paragraphs[i].includes(':')) {
// Create a new insight section
currentInsight = document.createElement('div');
currentInsight.className = 'insight-level';
const header = document.createElement('h4');
header.textContent = `Insight ${insightCounter}: ${paragraphs[i].split(':')[1].trim()}`;
currentInsight.appendChild(header);
outputEl.appendChild(currentInsight);
insightCounter++;
} else {
// Add paragraph to current insight or directly to output
const para = document.createElement('p');
para.textContent = paragraphs[i];
para.style.opacity = 0;
para.style.transform = 'translateY(10px)';
para.style.transition = 'opacity 0.5s, transform 0.5s';
if (currentInsight) {
currentInsight.appendChild(para);
} else {
outputEl.appendChild(para);
}
// Animate paragraph appearance
await new Promise(resolve => setTimeout(resolve, 300));
para.style.opacity = 1;
para.style.transform = 'translateY(0)';
}
}
}
// Update status
updateStatus(`Analysis of "${expression}" complete using ${config.modes[state.currentMode].name}`);
};
const generateTemplateBasedAnalysis = (expression) => {
// Template-based generation
let output = '';
const templates = config.llmlAnalysis[state.currentMode];
// Generate 3 insights
for (let i = 0; i < 3; i++) {
// Select template for insight level
const templateIndex = i % templates.length;
const template = templates[templateIndex];
// Add insight header
output += `Insight ${i+1}: ${state.currentMode.charAt(0).toUpperCase() + state.currentMode.slice(1)} Analysis\n\n`;
// Fill in template
let insight = template.replace('{expression}', expression);
// Add process
const processes = config.recursion.processes;
const process = processes[Math.floor(Math.random() * processes.length)];
insight = insight.replace('{process}', process);
// Add insight
const insights = config.recursion.insights;
const insightText = insights[Math.floor(Math.random() * insights.length)];
insight = insight.replace('{insight}', insightText);
// Add number
const number = Math.floor(Math.random() * 8) + 3; // 3-10
insight = insight.replace('{number}', number);
output += insight + '\n\n';
}
return output;
};
const updateStatus = (message) => {
statusEl.textContent = message;
statusEl.classList.add('pulsing');
setTimeout(() => {
statusEl.classList.remove('pulsing');
}, 1000);
};
const handleEvolve = async () => {
if (state.evolutionInProgress) return;
state.evolutionInProgress = true;
const depth = state.recursionDepth;
// Update status
updateStatus(`Initiating meta-recursive evolution cycle (depth: ${depth})...`);
// Notify other users if connected
if (state.multiplayer.connected) {
room.send({
type: 'evolution_triggered',
depth: depth,
username: state.multiplayer.username
});
}
// Calculate duration based on depth
const duration = config.evolution.baseDuration + (depth * config.evolution.depthMultiplier);
// Trigger evolution animation
visualizationEl.classList.add('evolving');
// Gradually improve metrics during evolution
const startMetrics = { ...state.metrics };
const targetMetrics = {
symbolic: Math.min(startMetrics.symbolic + (depth * 15), 100),
quantum: Math.min(startMetrics.quantum + (depth * 12), 100),
holographic: Math.min(startMetrics.holographic + (depth * 10), 100),
meta: Math.min(startMetrics.meta + (depth * 8), 100)
};
// Evolution steps
for (let i = 0; i < config.evolution.evolutionSteps.length; i++) {
const step = config.evolution.evolutionSteps[i];
updateStatus(`Evolution step ${i+1}/${config.evolution.evolutionSteps.length}: ${step}`);
// Update metrics proportionally for each step
const progress = (i + 1) / config.evolution.evolutionSteps.length;
state.metrics = {
symbolic: startMetrics.symbolic + (targetMetrics.symbolic - startMetrics.symbolic) * progress,
quantum: startMetrics.quantum + (targetMetrics.quantum - startMetrics.quantum) * progress,
holographic: startMetrics.holographic + (targetMetrics.holographic - startMetrics.holographic) * progress,
meta: startMetrics.meta + (targetMetrics.meta - startMetrics.meta) * progress
};
updateMetricsBars();
// Add visual effects during evolution
if (i === 0) {
// Symbolic embedding - SONW pattern briefly
createParticleSystem('sonw');
} else if (i === 1) {
// Quantum processing - Afterthought pattern briefly
createParticleSystem('afterthought');
} else if (i === 2) {
// Holographic integration - Holographic pattern briefly
createParticleSystem('cognitive');
} else if (i === 3) {
// Meta-evolution - Return to integrated pattern with improvements
createParticleSystem('integrated');
}
// Wait between steps
await new Promise(resolve => setTimeout(resolve, duration / config.evolution.evolutionSteps.length));
}
// Evolution complete
updateStatus(`Meta-recursive evolution complete (depth: ${depth})`);
visualizationEl.classList.remove('evolving');
// Return to original mode if not already in integrated
if (state.currentMode !== 'integrated') {
createParticleSystem(state.currentMode);
}
// Update room state with new metrics
if (state.multiplayer.connected) {
room.party.updateRoomState({
metrics: state.metrics
});
}
state.evolutionInProgress = false;
};
const handleModeChange = (mode) => {
if (state.evolutionInProgress) return;
state.currentMode = mode;
// Update active button
updateSystemButtonsUI();
// Update visualization
createParticleSystem(mode);
// Update status
updateStatus(`System switched to ${config.modes[mode].name}`);
// Update presence
if (state.multiplayer.connected) {
room.party.updatePresence({
mode: mode
});
// Send mode change event
room.send({
type: 'mode_change',
mode: mode,
username: state.multiplayer.username
});
}
};
const updateMetricsBars = () => {
document.getElementById('symbolicBar').style.width = `${state.metrics.symbolic}%`;
document.getElementById('quantumBar').style.width = `${state.metrics.quantum}%`;
document.getElementById('holoBar').style.width = `${state.metrics.holographic}%`;
document.getElementById('metaBar').style.width = `${state.metrics.meta}%`;
};
const initMultiplayer = async () => {
try {
// Get current user
state.multiplayer.userId = room.party.client.id;
state.multiplayer.username = room.party.client.username;
// Assign a color to the user
const colorIndex = Object.keys(room.party.peers).length % config.multiplayer.userColors.length;
state.multiplayer.userColor = config.multiplayer.userColors[colorIndex];
// Update presence with user info and initial state
room.party.updatePresence({
username: state.multiplayer.username,
color: state.multiplayer.userColor,
mode: state.currentMode,
cursorX: 0,
cursorY: 0,
isActive: true
});
// Subscribe to presence updates
room.party.subscribePresence(handlePresenceUpdates);
// Update room state with current system state if we're the first user
if (Object.keys(room.party.peers).length === 1) {
room.party.updateRoomState({
currentMode: state.currentMode,
metrics: state.metrics,
sharedAnalyses: []
});
}
// Subscribe to room state changes
room.party.subscribeRoomState(handleRoomStateChanges);
// Set up event listeners
room.onmessage = handleMessage;
// Set up mouse move for cursor sharing
visualizationEl.addEventListener('mousemove', handleMouseMove);
// Set up touch move for mobile
visualizationEl.addEventListener('touchmove', handleTouchMove);
state.multiplayer.connected = true;
showNotification(`Connected as ${state.multiplayer.username}`);
} catch (error) {
console.error('Error initializing multiplayer:', error);
showNotification('Failed to connect to multiplayer session');
}
};
const handlePresenceUpdates = (presence) => {
// Update local state with researchers
state.multiplayer.researchers = presence;
// Update UI
updateResearchersUI();
updateUserCursors();
// Update user count
const userCount = Object.keys(presence).length;
userCountEl.textContent = userCount;
};
const handleRoomStateChanges = (roomState) => {
// Check if room state is defined
if (!roomState) return;
// Update mode if changed by another user
if (roomState.currentMode && roomState.currentMode !== state.currentMode) {
state.currentMode = roomState.currentMode;
updateSystemButtonsUI();
createParticleSystem(state.currentMode);
}
// Update metrics if changed
if (roomState.metrics) {
state.metrics = roomState.metrics;
updateMetricsBars();
}
// Update shared analyses if changed
if (roomState.sharedAnalyses) {
state.multiplayer.sharedAnalyses = roomState.sharedAnalyses;
updateSharedAnalysesUI();
}
};
const handleMessage = (event) => {
const data = event.data;
switch (data.type) {
case 'connected':
showNotification(`${data.username} connected`);
break;
case 'disconnected':
showNotification(`${data.username} disconnected`);
break;
case 'mode_change':
if (data.clientId !== state.multiplayer.userId) {
showNotification(`${data.username} switched mode to ${config.modes[data.mode].name}`);
}
break;
case 'analysis_shared':
if (data.clientId !== state.multiplayer.userId) {
showNotification(`${data.username} shared an analysis of "${data.expression}"`);
}
break;
case 'evolution_triggered':
if (data.clientId !== state.multiplayer.userId) {
showNotification(`${data.username} triggered evolution (depth: ${data.depth})`);
}
break;
}
};
const updateResearchersUI = () => {
researchersEl.innerHTML = '';
for (const userId in state.multiplayer.researchers) {
const researcher = state.multiplayer.researchers[userId];
if (!researcher.username || !researcher.isActive) continue;
const researcherEl = document.createElement('div');
researcherEl.className = 'researcher';
const colorEl = document.createElement('div');
colorEl.className = 'researcher-color';
colorEl.style.backgroundColor = researcher.color;
const nameEl = document.createElement('div');
nameEl.className = 'researcher-name';
nameEl.textContent = researcher.username;
researcherEl.appendChild(colorEl);
researcherEl.appendChild(nameEl);
researchersEl.appendChild(researcherEl);
}
};
const updateUserCursors = () => {
userCursorsEl.innerHTML = '';
for (const userId in state.multiplayer.researchers) {
// Skip own cursor
if (userId === state.multiplayer.userId) continue;
const researcher = state.multiplayer.researchers[userId];
if (!researcher.isActive) continue;
const cursorEl = document.createElement('div');
cursorEl.className = 'user-cursor';
cursorEl.style.backgroundColor = researcher.color;
cursorEl.style.left = `${researcher.cursorX}px`;
cursorEl.style.top = `${researcher.cursorY}px`;
// Add username label
const labelEl = document.createElement('div');
labelEl.style.position = 'absolute';
labelEl.style.top = '20px';
labelEl.style.left = '10px';
labelEl.style.fontSize = '12px';
labelEl.style.whiteSpace = 'nowrap';
labelEl.textContent = researcher.username;
cursorEl.appendChild(labelEl);
userCursorsEl.appendChild(cursorEl);
}
};
const handleMouseMove = (event) => {
if (!state.multiplayer.connected) return;
// Get cursor position relative to visualization element
const rect = visualizationEl.getBoundingClientRect();
const x = event.clientX - rect.left;
const y = event.clientY - rect.top;
// Update presence with cursor position
room.party.updatePresence({
cursorX: x,
cursorY: y
});
};
const handleTouchMove = (event) => {
if (!state.multiplayer.connected || !event.touches[0]) return;
// Get touch position relative to visualization element
const rect = visualizationEl.getBoundingClientRect();
const x = event.touches[0].clientX - rect.left;
const y = event.touches[0].clientY - rect.top;
// Update presence with cursor position
room.party.updatePresence({
cursorX: x,
cursorY: y
});
};
const shareAnalysis = () => {
if (!state.multiplayer.connected) return;
// Get current output content
const outputContent = outputEl.innerText;
// Check if there's content to share
if (!outputContent || outputContent.includes('placeholder')) {
showNotification('Nothing to share. Process an expression first.');
return;
}
// Get the current expression
let expression = conceptInput.value.trim();
if (!expression) {
// Use selected expression from dropdown
const selectedKey = symbolSelector.value;
expression = config.symbolicExpressions[selectedKey].expression;
}
// Create shared analysis
const sharedAnalysis = {
id: Date.now().toString(),
username: state.multiplayer.username,
userId: state.multiplayer.userId,
color: state.multiplayer.userColor,
timestamp: new Date().toISOString(),
expression,
content: outputContent.substring(0, config.multiplayer.sharingSettings.characterLimit),
mode: state.currentMode
};
// Get current shared analyses
const sharedAnalyses = [...state.multiplayer.sharedAnalyses];
// Add new analysis
sharedAnalyses.push(sharedAnalysis);
// Limit number of shared analyses
if (sharedAnalyses.length > config.multiplayer.sharingSettings.maxSharedAnalyses) {
sharedAnalyses.shift();
}
// Update room state
room.party.updateRoomState({
sharedAnalyses
});
// Send notification to other users
room.send({
type: 'analysis_shared',
expression,
username: state.multiplayer.username
});
showNotification('Analysis shared with all researchers');
};
const syncVisualization = () => {
if (!state.multiplayer.connected) return;
// Update room state with current state
room.party.updateRoomState({
currentMode: state.currentMode,
metrics: state.metrics
});
showNotification('Visualization synchronized with all researchers');
};
const updateSharedAnalysesUI = () => {
sharedAnalysesListEl.innerHTML = '';
if (state.multiplayer.sharedAnalyses.length === 0) {
sharedAnalysesListEl.innerHTML = '<p class="placeholder">No shared analyses yet.</p>';
return;
}
// Sort analyses by timestamp (newest first)
const sortedAnalyses = [...state.multiplayer.sharedAnalyses].sort((a, b) =>
new Date(b.timestamp) - new Date(a.timestamp)
);
for (const analysis of sortedAnalyses) {
const analysisEl = document.createElement('div');
analysisEl.className = 'shared-analysis';
const headerEl = document.createElement('div');
headerEl.className = 'shared-header';
const userEl = document.createElement('span');
userEl.style.color = analysis.color;
userEl.textContent = analysis.username;
const timeEl = document.createElement('span');
timeEl.textContent = formatTimestamp(analysis.timestamp);
headerEl.appendChild(userEl);
headerEl.appendChild(timeEl);
const expressionEl = document.createElement('div');
expressionEl.className = 'shared-expression';
expressionEl.textContent = `"${analysis.expression}"`;
const contentEl = document.createElement('div');
contentEl.className = 'shared-content';
contentEl.innerHTML = analysis.content;
analysisEl.appendChild(headerEl);
analysisEl.appendChild(expressionEl);
analysisEl.appendChild(contentEl);
sharedAnalysesListEl.appendChild(analysisEl);
}
};
const formatTimestamp = (timestamp) => {
const date = new Date(timestamp);
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
};
const showNotification = (message) => {
notificationEl.textContent = message;
notificationEl.classList.add('show');
setTimeout(() => {
notificationEl.classList.remove('show');
}, config.multiplayer.notificationDuration);
};
const updateSystemButtonsUI = () => {
systemButtons.forEach(btn => {
btn.classList.remove('active');
if (btn.id === `${state.currentMode}Btn`) {
btn.classList.add('active');
}
});
};
// Event listeners
window.addEventListener('DOMContentLoaded', () => {
// Initialize visualization
initVisualization();
// Initialize metrics display
updateMetricsBars();
// Initialize multiplayer
initMultiplayer();
// Mode buttons
document.getElementById('sonwBtn').addEventListener('click', () => handleModeChange('sonw'));
document.getElementById('afterthoughtBtn').addEventListener('click', () => handleModeChange('afterthought'));
document.getElementById('cognitiveBtn').addEventListener('click', () => handleModeChange('cognitive'));
document.getElementById('integratedBtn').addEventListener('click', () => handleModeChange('integrated'));
// Recursion depth slider
depthSlider.addEventListener('input', () => {
state.recursionDepth = parseInt(depthSlider.value);
depthValueEl.textContent = depthSlider.value;
});
// Evolution button
document.getElementById('evolveBtn').addEventListener('click', handleEvolve);
// Symbolic expression selector
symbolSelector.addEventListener('change', () => {
const selectedKey = symbolSelector.value;
const selectedExpression = config.symbolicExpressions[selectedKey];
conceptInput.placeholder = selectedExpression.expression;
// Display preview
outputEl.innerHTML = `
<p><strong>${selectedExpression.description}</strong></p>
<p class="symbolic-node">${selectedExpression.expression}</p>
<ul>
${selectedExpression.components.map(comp => `<li>${comp}</li>`).join('')}
</ul>
<p class="placeholder">Press "Process" to analyze this expression...</p>
`;
});
// Process symbolic expression
document.getElementById('processBtn').addEventListener('click', handleSymbolicProcess);
conceptInput.addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
handleSymbolicProcess();
}
});
// Collaborative features
shareBtn.addEventListener('click', shareAnalysis);
syncBtn.addEventListener('click', syncVisualization);
// Handle window unload to update presence
window.addEventListener('beforeunload', () => {
if (state.multiplayer.connected) {
room.party.updatePresence({
isActive: false
});
}
});
});