Mind-Candy / index.html
TheGreatUnknown's picture
Update index.html
4d3568c verified
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Collaborative Holographic Universe Simulation</title>
<style>
body {
font-family: 'Arial', sans-serif;
background: linear-gradient(135deg, #000, #111);
margin: 0;
padding: 0;
color: #ccf;
min-height: 100vh;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.container {
width: 90%;
max-width: 1200px;
margin: 0 auto;
padding: 20px;
}
.header {
text-align: center;
margin-bottom: 20px;
}
h1 {
font-size: 2.5rem;
color: #7cf;
text-shadow: 0 0 10px rgba(124, 255, 255, 0.7);
}
.quantum-simulator {
background: rgba(0, 0, 15, 0.7);
border-radius: 15px;
padding: 20px;
margin-bottom: 30px;
box-shadow: 0 0 20px rgba(124, 200, 255, 0.3);
}
.env-setup {
background: rgba(15, 0, 30, 0.7);
border-radius: 15px;
padding: 20px;
margin-bottom: 30px;
box-shadow: 0 0 20px rgba(180, 120, 255, 0.3);
}
.analysis {
background: rgba(0, 30, 15, 0.7);
border-radius: 15px;
padding: 20px;
box-shadow: 0 0 20px rgba(120, 255, 170, 0.3);
}
.section-title {
color: #adf;
font-size: 1.6rem;
margin-bottom: 15px;
}
.row {
display: flex;
flex-wrap: wrap;
margin: 0 -10px;
}
.column {
flex: 1 1 300px;
margin: 10px;
}
canvas {
width: 100%;
height: auto;
background: #000;
border-radius: 10px;
max-height: 300px;
}
button {
background: linear-gradient(45deg, #4a7bd1, #7a4ad1);
color: white;
border: none;
padding: 12px 20px;
border-radius: 5px;
font-size: 16px;
cursor: pointer;
margin-top: 10px;
transition: all 0.3s;
}
button:hover {
transform: scale(1.05);
box-shadow: 0 0 15px rgba(124, 200, 255, 0.6);
}
.control-panel {
display: flex;
flex-wrap: wrap;
gap: 10px;
margin-bottom: 15px;
}
.parameter-control {
display: flex;
flex-direction: column;
min-width: 120px;
}
label {
margin-bottom: 5px;
color: #8cf;
}
input {
padding: 8px;
border-radius: 4px;
border: 1px solid #446;
background: #112;
color: #ddf;
}
.code-block {
background: #001;
padding: 15px;
border-radius: 5px;
font-family: monospace;
overflow-x: auto;
color: #8df;
margin-top: 10px;
}
.visualization {
width: 100%;
height: 280px;
margin-top: 15px;
position: relative;
}
.visualizer-canvas {
background: linear-gradient(to bottom, #000510, #001030);
border: 1px solid #333366;
width: 100%;
height: 100%;
border-radius: 8px;
}
.metrics {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(200px, 1fr));
gap: 15px;
margin-top: 15px;
}
.metric-card {
background: rgba(20, 30, 50, 0.6);
padding: 15px;
border-radius: 8px;
text-align: center;
}
.metric-value {
font-size: 1.8rem;
color: #7df;
margin: 10px 0;
font-weight: bold;
}
.metric-label {
color: #adf;
font-size: 0.9rem;
}
@media (max-width: 768px) {
.column {
flex: 1 1 100%;
}
}
.user-avatar {
width: 30px;
height: 30px;
border-radius: 50%;
margin-right: 5px;
}
.users-list {
background: rgba(10, 20, 40, 0.7);
border-radius: 10px;
padding: 15px;
margin-bottom: 20px;
max-height: 150px;
overflow-y: auto;
}
.user-container {
display: flex;
align-items: center;
margin-bottom: 8px;
color: #adf;
font-size: 0.9rem;
}
.user-cursor {
position: absolute;
pointer-events: none;
z-index: 1000;
font-size: 12px;
display: flex;
flex-direction: column;
align-items: center;
}
.cursor-pointer {
width: 20px;
height: 20px;
border-radius: 50%;
}
.cursor-label {
background: rgba(0, 0, 0, 0.7);
color: white;
padding: 2px 5px;
border-radius: 3px;
margin-top: 5px;
white-space: nowrap;
}
.chat-container {
background: rgba(10, 20, 40, 0.7);
border-radius: 10px;
padding: 15px;
margin-top: 20px;
display: flex;
flex-direction: column;
height: 200px;
}
.chat-messages {
flex-grow: 1;
overflow-y: auto;
margin-bottom: 10px;
color: #ddf;
}
.chat-input-container {
display: flex;
}
.chat-input {
flex-grow: 1;
padding: 8px;
border-radius: 4px;
border: 1px solid #446;
background: #112;
color: #ddf;
margin-right: 5px;
}
.chat-send {
background: linear-gradient(45deg, #4a7bd1, #7a4ad1);
color: white;
border: none;
padding: 8px 15px;
border-radius: 5px;
cursor: pointer;
}
.message {
margin-bottom: 8px;
}
.message-user {
font-weight: bold;
color: #7cf;
}
.message-text {
color: #ccf;
}
</style>
</head>
<body>
<div class="container">
<div class="header">
<h1>Collaborative Holographic Universe Simulation</h1>
<p>Explore quantum circuits and holographic frameworks together in real-time</p>
</div>
<div class="users-list" id="users-list">
<h3>Connected Users</h3>
<div id="users-container"></div>
</div>
<div class="quantum-simulator">
<h2 class="section-title">Quantum Circuit Setup</h2>
<div class="row">
<div class="column">
<div class="control-panel">
<div class="parameter-control">
<label for="num-qubits">Number of Qubits</label>
<input type="number" id="num-qubits" min="1" max="8" value="3">
</div>
<div class="parameter-control">
<label for="num-shots">Number of Shots</label>
<input type="number" id="num-shots" min="100" max="10000" value="1024">
</div>
</div>
<div class="code-block">
<pre>
# Define a quantum register and circuit
qr = QuantumRegister(3, 'q')
cr = ClassicalRegister(3, 'c')
qc = QuantumCircuit(qr, cr)
# Apply Hadamard gates to create superposition
for i in range(qr.size()):
qc.h(qr[i])
# Apply CNOT gate to entangle qubits
qc.cx(qr[0], qr[1])
# Measure all qubits
qc.measure(qr, cr)</pre>
</div>
<button id="run-circuit">Run Quantum Circuit</button>
</div>
<div class="column">
<div class="visualization">
<canvas id="circuit-canvas" class="visualizer-canvas"></canvas>
</div>
<div class="metrics">
<div class="metric-card">
<div class="metric-label">Entanglement Measure</div>
<div class="metric-value" id="entanglement-value">0.82</div>
</div>
<div class="metric-card">
<div class="metric-label">Coherence</div>
<div class="metric-value" id="coherence-value">0.65</div>
</div>
</div>
</div>
</div>
</div>
<div class="env-setup">
<h2 class="section-title">Holographic Environment Setup</h2>
<div class="row">
<div class="column">
<div class="control-panel">
<div class="parameter-control">
<label for="time-const">Time Constant (t)</label>
<input type="number" id="time-const" min="0" max="3" value="1">
</div>
<div class="parameter-control">
<label for="space-scale">Space Scale (s)</label>
<input type="number" id="space-scale" min="0" max="3" value="2">
</div>
<div class="parameter-control">
<label for="mass-value">Mass Value (m)</label>
<input type="number" id="mass-value" min="0" max="3" value="3">
</div>
<div class="parameter-control">
<label for="dimension-num">Dimensions (d)</label>
<input type="number" id="dimension-num" min="0" max="3" value="1">
</div>
</div>
<div class="code-block">
<pre>
# Define environment variables (2-bit representations)
t = 0b01 # Planck time (scaled)
s = 0b10 # Scale of space
m = 0b11 # Simplified number of atoms
d = 0b01 # Number of dimensions
# Concatenate to form 8-bit environment label
env_label = f"{t:02b}{s:02b}{m:02b}{d:02b}"
# Create environment state vector
env_state = Statevector.from_label(env_label)</pre>
</div>
<button id="update-env">Update Environment</button>
</div>
<div class="column">
<div class="visualization">
<canvas id="environment-canvas" class="visualizer-canvas"></canvas>
</div>
<div class="metrics">
<div class="metric-card">
<div class="metric-label">Environment Label</div>
<div class="metric-value" id="env-label-value">01101101</div>
</div>
<div class="metric-card">
<div class="metric-label">State Complexity</div>
<div class="metric-value" id="complexity-value">3.14</div>
</div>
</div>
</div>
</div>
</div>
<div class="analysis">
<h2 class="section-title">Analysis and Results</h2>
<div class="row">
<div class="column">
<div class="visualization">
<canvas id="histogram-canvas" class="visualizer-canvas"></canvas>
</div>
<div class="metrics">
<div class="metric-card">
<div class="metric-label">Mean Count</div>
<div class="metric-value" id="mean-count">128.00</div>
</div>
<div class="metric-card">
<div class="metric-label">Variance</div>
<div class="metric-value" id="variance-count">42.56</div>
</div>
</div>
</div>
<div class="column">
<div class="visualization">
<canvas id="evolution-canvas" class="visualizer-canvas"></canvas>
</div>
<div class="metrics">
<div class="metric-card">
<div class="metric-label">State Fidelity</div>
<div class="metric-value" id="fidelity-value">0.78</div>
</div>
<div class="metric-card">
<div class="metric-label">Quantum Entropy</div>
<div class="metric-value" id="entropy-value">1.23</div>
</div>
</div>
</div>
</div>
<button id="run-analysis">Run Full Analysis</button>
</div>
<div class="chat-container">
<div class="chat-messages" id="chat-messages"></div>
<div class="chat-input-container">
<input type="text" class="chat-input" id="chat-input" placeholder="Type your message...">
<button class="chat-send" id="chat-send">Send</button>
</div>
</div>
</div>
<script>
// Initialize WebSocket for multiplayer functionality
const room = new WebsimSocket();
let clientId, username;
const cursors = {};
// Map to track user colors
const userColors = {};
// Track when user last moved cursor (to avoid too many updates)
let lastCursorUpdate = 0;
// Initialize canvases
const canvases = {
circuit: document.getElementById('circuit-canvas'),
environment: document.getElementById('environment-canvas'),
histogram: document.getElementById('histogram-canvas'),
evolution: document.getElementById('evolution-canvas')
};
// Initialize contexts
const contexts = {};
for (const [key, canvas] of Object.entries(canvases)) {
contexts[key] = canvas.getContext('2d');
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
}
// Simulation state
const state = {
qubits: 3,
shots: 1024,
environmentParams: {
t: 1, // Time constant
s: 2, // Space scale
m: 3, // Mass value
d: 1 // Dimensions
},
measurements: {},
environmentState: {},
statistics: {
mean: 128.0,
variance: 42.56,
fidelity: 0.78,
entropy: 1.23,
entanglement: 0.82,
coherence: 0.65,
complexity: 3.14
}
};
// Draw quantum circuit visualization
function drawCircuit() {
const ctx = contexts.circuit;
const width = canvases.circuit.width;
const height = canvases.circuit.height;
ctx.clearRect(0, 0, width, height);
// Draw background grid
ctx.strokeStyle = 'rgba(100, 150, 255, 0.1)';
ctx.lineWidth = 1;
const gridSize = 20;
for (let x = 0; x <= width; x += gridSize) {
ctx.beginPath();
ctx.moveTo(x, 0);
ctx.lineTo(x, height);
ctx.stroke();
}
for (let y = 0; y <= height; y += gridSize) {
ctx.beginPath();
ctx.moveTo(0, y);
ctx.lineTo(width, y);
ctx.stroke();
}
// Draw qubit lines
const qubitSpacing = height / (state.qubits + 1);
ctx.strokeStyle = 'rgba(100, 200, 255, 0.8)';
ctx.lineWidth = 2;
for (let i = 0; i < state.qubits; i++) {
const y = (i + 1) * qubitSpacing;
ctx.beginPath();
ctx.moveTo(50, y);
ctx.lineTo(width - 50, y);
ctx.stroke();
// Qubit label
ctx.fillStyle = 'rgba(150, 220, 255, 0.8)';
ctx.font = '12px Arial';
ctx.textAlign = 'right';
ctx.fillText(`q${i}`, 40, y + 4);
}
// Draw Hadamard gates
const gateWidth = 30;
const gateHeight = 30;
const hGateX = 100;
for (let i = 0; i < state.qubits; i++) {
const y = (i + 1) * qubitSpacing - gateHeight / 2;
ctx.fillStyle = 'rgba(100, 150, 255, 0.7)';
ctx.fillRect(hGateX, y, gateWidth, gateHeight);
ctx.fillStyle = 'white';
ctx.font = 'bold 16px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText('H', hGateX + gateWidth / 2, y + gateHeight / 2);
}
// Draw CNOT gate
const cnotX = 200;
const controlY = 1 * qubitSpacing;
const targetY = 2 * qubitSpacing;
// Control point
ctx.fillStyle = 'rgba(255, 100, 100, 0.8)';
ctx.beginPath();
ctx.arc(cnotX, controlY, 5, 0, Math.PI * 2);
ctx.fill();
// Line connecting control and target
ctx.strokeStyle = 'rgba(255, 100, 100, 0.8)';
ctx.beginPath();
ctx.moveTo(cnotX, controlY);
ctx.lineTo(cnotX, targetY);
ctx.stroke();
// Target circle
ctx.beginPath();
ctx.arc(cnotX, targetY, 15, 0, Math.PI * 2);
ctx.stroke();
// Plus symbol
ctx.beginPath();
ctx.moveTo(cnotX - 10, targetY);
ctx.lineTo(cnotX + 10, targetY);
ctx.moveTo(cnotX, targetY - 10);
ctx.lineTo(cnotX, targetY + 10);
ctx.stroke();
// Draw measurement operations
const measureX = 300;
for (let i = 0; i < state.qubits; i++) {
const y = (i + 1) * qubitSpacing;
// Measurement symbol
ctx.strokeStyle = 'rgba(150, 255, 150, 0.8)';
ctx.fillStyle = 'rgba(100, 200, 100, 0.3)';
// Box
ctx.fillRect(measureX, y - 15, 40, 30);
ctx.strokeRect(measureX, y - 15, 40, 30);
// Meter symbol
ctx.beginPath();
ctx.moveTo(measureX + 10, y - 5);
ctx.lineTo(measureX + 10, y + 5);
ctx.lineTo(measureX + 30, y - 5);
ctx.lineTo(measureX + 30, y + 5);
ctx.stroke();
}
}
// Draw holographic environment visualization
function drawEnvironment() {
const ctx = contexts.environment;
const width = canvases.environment.width;
const height = canvases.environment.height;
ctx.clearRect(0, 0, width, height);
// Draw background
const gradient = ctx.createLinearGradient(0, 0, width, height);
gradient.addColorStop(0, 'rgba(0, 10, 30, 0.5)');
gradient.addColorStop(1, 'rgba(30, 0, 60, 0.5)');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
// Update environment label display
const envLabel = `${state.environmentParams.t.toString(2).padStart(2, '0')}${state.environmentParams.s.toString(2).padStart(2, '0')}${state.environmentParams.m.toString(2).padStart(2, '0')}${state.environmentParams.d.toString(2).padStart(2, '0')}`;
document.getElementById('env-label-value').textContent = envLabel;
// Draw bit representations
const bitSize = 30;
const startX = width / 2 - (8 * bitSize) / 2;
const y = height / 2;
for (let i = 0; i < 8; i++) {
const x = startX + i * bitSize;
const bitValue = envLabel[i];
ctx.fillStyle = bitValue === '1' ? 'rgba(100, 200, 255, 0.8)' : 'rgba(50, 50, 100, 0.5)';
ctx.fillRect(x, y - bitSize / 2, bitSize - 2, bitSize);
ctx.fillStyle = 'white';
ctx.font = '14px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(bitValue, x + bitSize / 2 - 1, y);
}
// Draw parameter indicators
const paramRadius = 50;
const centerX = width / 2;
const centerY = height / 2 - 70;
// Draw parameter circles
const params = [
{ name: 't', value: state.environmentParams.t, color: 'rgba(255, 100, 100, 0.7)' },
{ name: 's', value: state.environmentParams.s, color: 'rgba(100, 255, 100, 0.7)' },
{ name: 'm', value: state.environmentParams.m, color: 'rgba(100, 100, 255, 0.7)' },
{ name: 'd', value: state.environmentParams.d, color: 'rgba(255, 255, 100, 0.7)' }
];
for (let i = 0; i < params.length; i++) {
const angle = (i * Math.PI / 2) - Math.PI / 4;
const x = centerX + Math.cos(angle) * paramRadius;
const y = centerY + Math.sin(angle) * paramRadius;
const param = params[i];
// Circle
ctx.fillStyle = param.color;
ctx.beginPath();
ctx.arc(x, y, 20, 0, Math.PI * 2);
ctx.fill();
// Label
ctx.fillStyle = 'white';
ctx.font = 'bold 16px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
ctx.fillText(param.name, x, y - 2);
// Value
ctx.font = '12px Arial';
ctx.fillText(param.value, x, y + 12);
}
// Draw connecting lines
ctx.strokeStyle = 'rgba(150, 150, 255, 0.4)';
ctx.lineWidth = 1;
for (let i = 0; i < params.length; i++) {
const angle1 = (i * Math.PI / 2) - Math.PI / 4;
const x1 = centerX + Math.cos(angle1) * paramRadius;
const y1 = centerY + Math.sin(angle1) * paramRadius;
for (let j = i + 1; j < params.length; j++) {
const angle2 = (j * Math.PI / 2) - Math.PI / 4;
const x2 = centerX + Math.cos(angle2) * paramRadius;
const y2 = centerY + Math.sin(angle2) * paramRadius;
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
}
// Draw holographic effect
for (let i = 0; i < 50; i++) {
const angle = Math.random() * Math.PI * 2;
const distance = Math.random() * 100 + 30;
const x = centerX + Math.cos(angle) * distance;
const y = centerY + Math.sin(angle) * distance;
ctx.fillStyle = `rgba(150, 220, 255, ${Math.random() * 0.2})`;
ctx.beginPath();
ctx.arc(x, y, Math.random() * 5 + 1, 0, Math.PI * 2);
ctx.fill();
}
// Update complexity metric
const complexity = (1 + Math.sin(Date.now() / 1000) * 0.1) * 3.14;
document.getElementById('complexity-value').textContent = complexity.toFixed(2);
}
// Draw measurement histogram
function drawHistogram() {
const ctx = contexts.histogram;
const width = canvases.histogram.width;
const height = canvases.histogram.height;
ctx.clearRect(0, 0, width, height);
// Generate some sample measurement data based on current qubits
const possibleOutcomes = Math.pow(2, state.qubits);
const measurements = {};
let total = 0;
// Create plausible quantum distribution
for (let i = 0; i < possibleOutcomes; i++) {
const bitString = i.toString(2).padStart(state.qubits, '0');
// Generate values with a slight bias towards balanced states
let probability = Math.random();
// Add interference pattern for more realistic quantum results
const hammingWeight = bitString.split('').filter(bit => bit === '1').length;
const balance = Math.abs(hammingWeight - state.qubits / 2) / state.qubits;
probability = probability * (1 - balance * 0.5);
// Add entanglement effect (correlations between bits 0 and 1)
if (state.qubits >= 2 && bitString[0] === bitString[1]) {
probability *= 1.5;
}
const count = Math.floor(probability * state.shots / possibleOutcomes * 2);
measurements[bitString] = count;
total += count;
}
// Normalize to ensure total equals shots
for (const outcome in measurements) {
measurements[outcome] = Math.floor(measurements[outcome] * state.shots / total);
}
// Calculate statistics
const values = Object.values(measurements);
const mean = values.reduce((sum, val) => sum + val, 0) / values.length;
const variance = values.reduce((sum, val) => sum + Math.pow(val - mean, 2), 0) / values.length;
state.statistics.mean = mean;
state.statistics.variance = variance;
// Update metrics display
document.getElementById('mean-count').textContent = mean.toFixed(2);
document.getElementById('variance-count').textContent = variance.toFixed(2);
// Draw histogram
const outcomes = Object.keys(measurements).sort();
const barWidth = width / outcomes.length;
const maxHeight = height - 40;
const maxCount = Math.max(...Object.values(measurements));
// Draw bars
for (let i = 0; i < outcomes.length; i++) {
const outcome = outcomes[i];
const count = measurements[outcome];
const barHeight = (count / maxCount) * maxHeight;
const hue = 240 - (i / outcomes.length) * 60;
ctx.fillStyle = `hsla(${hue}, 80%, 60%, 0.7)`;
ctx.fillRect(i * barWidth, height - barHeight - 30, barWidth - 2, barHeight);
// Label for bar
if (barWidth > 25) {
ctx.fillStyle = 'white';
ctx.font = '10px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
ctx.fillText(outcome, i * barWidth + barWidth / 2, height - 25);
}
}
// Draw axes
ctx.strokeStyle = 'rgba(200, 200, 255, 0.5)';
ctx.lineWidth = 1;
// X axis
ctx.beginPath();
ctx.moveTo(0, height - 30);
ctx.lineTo(width, height - 30);
ctx.stroke();
// Y axis
ctx.beginPath();
ctx.moveTo(0, 0);
ctx.lineTo(0, height - 30);
ctx.stroke();
// Y axis label
ctx.save();
ctx.translate(15, height / 2);
ctx.rotate(-Math.PI / 2);
ctx.fillStyle = 'rgba(200, 200, 255, 0.8)';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.fillText('Counts', 0, 0);
ctx.restore();
// X axis label
ctx.fillStyle = 'rgba(200, 200, 255, 0.8)';
ctx.font = '12px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'top';
ctx.fillText('Measurement Outcomes', width / 2, height - 10);
}
// Draw state evolution visualization
function drawEvolution() {
const ctx = contexts.evolution;
const width = canvases.evolution.width;
const height = canvases.evolution.height;
ctx.clearRect(0, 0, width, height);
// Create gradient background
const gradient = ctx.createRadialGradient(width / 2, height / 2, 0, width / 2, height / 2, height / 2);
gradient.addColorStop(0, 'rgba(10, 20, 40, 0.8)');
gradient.addColorStop(1, 'rgba(0, 5, 20, 0.8)');
ctx.fillStyle = gradient;
ctx.fillRect(0, 0, width, height);
// Draw evolution effect
const time = Date.now() / 1000;
const centerX = width / 2;
const centerY = height / 2;
// Draw quantum state amplitudes
const stateCount = Math.pow(2, state.qubits);
const radius = Math.min(width, height) * 0.35;
for (let i = 0; i < stateCount; i++) {
const angle = (i / stateCount) * Math.PI * 2;
const x = centerX + Math.cos(angle) * radius;
const y = centerY + Math.sin(angle) * radius;
// Amplitude visualization
const amplitude = 0.3 + 0.7 * Math.abs(Math.sin(time + i * 0.7));
// State vector
ctx.strokeStyle = `rgba(100, 200, 255, ${amplitude * 0.7})`;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(centerX, centerY);
ctx.lineTo(x, y);
ctx.stroke();
// Amplitude point
ctx.fillStyle = `rgba(150, 220, 255, ${amplitude})`;
ctx.beginPath();
ctx.arc(x, y, 5 + amplitude * 3, 0, Math.PI * 2);
ctx.fill();
// State label
const bitString = i.toString(2).padStart(state.qubits, '0');
ctx.fillStyle = 'rgba(255, 255, 255, 0.7)';
ctx.font = '10px Arial';
ctx.textAlign = 'center';
ctx.textBaseline = 'middle';
const textX = centerX + Math.cos(angle) * (radius + 15);
const textY = centerY + Math.sin(angle) * (radius + 15);
ctx.fillText(bitString, textX, textY);
}
// Draw environment influence (adaptive effects)
const envInfluence = Math.sin(time * 0.5) * 0.5 + 0.5;
// Draw interference pattern
ctx.strokeStyle = `rgba(100, 255, 200, ${0.1 + envInfluence * 0.2})`;
ctx.lineWidth = 1;
for (let i = 0; i < stateCount; i++) {
const angle1 = (i / stateCount) * Math.PI * 2;
const x1 = centerX + Math.cos(angle1) * radius;
const y1 = centerY + Math.sin(angle1) * radius;
for (let j = i + 1; j < stateCount; j++) {
// Only connect interfering states
if ((i ^ j) & 1) {
const angle2 = (j / stateCount) * Math.PI * 2;
const x2 = centerX + Math.cos(angle2) * radius;
const y2 = centerY + Math.sin(angle2) * radius;
// Draw interference line
ctx.beginPath();
ctx.moveTo(x1, y1);
ctx.lineTo(x2, y2);
ctx.stroke();
}
}
}
// Draw holographic projection
ctx.fillStyle = `rgba(100, 200, 255, ${0.05 + envInfluence * 0.1})`;
for (let i = 0; i < 3; i++) {
const projRadius = radius * (0.5 + i * 0.2);
ctx.beginPath();
ctx.arc(centerX, centerY, projRadius, 0, Math.PI * 2);
ctx.fill();
}
// Update metrics based on time
const fidelity = 0.5 + 0.3 * Math.sin(time * 0.3);
const entropy = 1 + 0.3 * Math.cos(time * 0.7);
const entanglement = 0.7 + 0.2 * Math.sin(time * 0.5);
const coherence = 0.5 + 0.2 * Math.cos(time * 0.4);
// Update metrics display
document.getElementById('fidelity-value').textContent = fidelity.toFixed(2);
document.getElementById('entropy-value').textContent = entropy.toFixed(2);
document.getElementById('entanglement-value').textContent = entanglement.toFixed(2);
document.getElementById('coherence-value').textContent = coherence.toFixed(2);
}
// Initialize multiplayer functionality
function initMultiplayer() {
// Get client info
clientId = room.party.client.id;
username = room.party.client.username;
// Setup message handler
room.onmessage = (event) => {
const data = event.data;
switch (data.type) {
case "connected":
addUserToList(data.clientId, data.username);
addSystemMessage(`${data.username} joined the simulation`);
break;
case "disconnected":
removeUserFromList(data.clientId);
removeCursor(data.clientId);
addSystemMessage(`${data.username} left the simulation`);
break;
case "chat":
addChatMessage(data.username, data.message);
break;
case "cursor_move":
updateCursor(data.clientId, data.x, data.y, data.username);
break;
case "parameter_change":
handleParameterChange(data.parameter, data.value, data.username);
break;
case "run_circuit":
handleRunCircuit(data.username);
break;
case "update_env":
handleUpdateEnv(data.username);
break;
case "run_analysis":
handleRunAnalysis(data.username);
break;
}
};
// Listen for mouse movement to broadcast cursor position
document.addEventListener('mousemove', (e) => {
const now = Date.now();
if (now - lastCursorUpdate > 50) { // Limit updates to every 50ms
lastCursorUpdate = now;
room.send({
type: "cursor_move",
x: e.clientX,
y: e.clientY
});
}
});
// Setup chat functionality
document.getElementById('chat-send').addEventListener('click', sendChatMessage);
document.getElementById('chat-input').addEventListener('keypress', (e) => {
if (e.key === 'Enter') {
sendChatMessage();
}
});
// Update existing button handlers to broadcast events
document.getElementById('run-circuit').addEventListener('click', function() {
// Existing handler code
drawCircuit();
setTimeout(() => {
drawHistogram();
drawEvolution();
}, 500);
// Broadcast the event
room.send({
type: "run_circuit"
});
});
document.getElementById('update-env').addEventListener('click', function() {
// Existing handler code
drawEnvironment();
setTimeout(() => {
drawEvolution();
}, 500);
// Broadcast the event
room.send({
type: "update_env"
});
});
document.getElementById('run-analysis').addEventListener('click', function() {
// Existing handler code
drawCircuit();
setTimeout(() => {
drawEnvironment();
setTimeout(() => {
drawHistogram();
setTimeout(() => {
drawEvolution();
}, 300);
}, 300);
}, 300);
// Broadcast the event
room.send({
type: "run_analysis"
});
});
// Update input handlers to broadcast parameter changes
const parameterInputs = [
'num-qubits', 'num-shots', 'time-const',
'space-scale', 'mass-value', 'dimension-num'
];
parameterInputs.forEach(inputId => {
const inputElement = document.getElementById(inputId);
// Store original event handler
const originalHandler = inputElement.onchange;
// Add new handler that broadcasts changes
inputElement.addEventListener('change', function(e) {
// Call original handler if it exists
if (originalHandler) originalHandler(e);
// Broadcast parameter change
room.send({
type: "parameter_change",
parameter: inputId,
value: parseInt(e.target.value)
});
});
});
// Initialize users list
updateUsersList();
}
// Add user to the connected users list
function addUserToList(userId, userName) {
if (!userColors[userId]) {
// Assign a random color for this user
const hue = Math.floor(Math.random() * 360);
userColors[userId] = `hsl(${hue}, 70%, 60%)`;
}
updateUsersList();
}
// Remove user from the connected users list
function removeUserFromList(userId) {
updateUsersList();
}
// Update the entire users list
function updateUsersList() {
const usersContainer = document.getElementById('users-container');
usersContainer.innerHTML = '';
for (const clientId in room.party.peers) {
const { username } = room.party.peers[clientId];
const color = userColors[clientId] || 'hsl(200, 70%, 60%)';
const userDiv = document.createElement('div');
userDiv.className = 'user-container';
const userAvatar = document.createElement('div');
userAvatar.className = 'user-avatar';
userAvatar.style.backgroundColor = color;
const userNameSpan = document.createElement('span');
userNameSpan.textContent = username;
userDiv.appendChild(userAvatar);
userDiv.appendChild(userNameSpan);
usersContainer.appendChild(userDiv);
}
}
// Update cursor position for a specific user
function updateCursor(userId, x, y, userName) {
// Don't show the current user's cursor
if (userId === clientId) return;
let cursor = cursors[userId];
if (!cursor) {
// Create cursor element if it doesn't exist
cursor = document.createElement('div');
cursor.className = 'user-cursor';
const pointer = document.createElement('div');
pointer.className = 'cursor-pointer';
const label = document.createElement('div');
label.className = 'cursor-label';
label.textContent = userName;
cursor.appendChild(pointer);
cursor.appendChild(label);
document.body.appendChild(cursor);
cursors[userId] = cursor;
}
// Get user's color or assign a new one
if (!userColors[userId]) {
const hue = Math.floor(Math.random() * 360);
userColors[userId] = `hsl(${hue}, 70%, 60%)`;
}
// Update cursor position and color
cursor.style.left = `${x}px`;
cursor.style.top = `${y}px`;
cursor.querySelector('.cursor-pointer').style.backgroundColor = userColors[userId];
}
// Remove cursor for a disconnected user
function removeCursor(userId) {
if (cursors[userId]) {
document.body.removeChild(cursors[userId]);
delete cursors[userId];
}
}
// Send a chat message
function sendChatMessage() {
const inputElement = document.getElementById('chat-input');
const message = inputElement.value.trim();
if (message) {
room.send({
type: "chat",
message: message
});
addChatMessage(username, message);
inputElement.value = '';
}
}
// Add a message to the chat box
function addChatMessage(userName, message) {
const messagesContainer = document.getElementById('chat-messages');
const messageDiv = document.createElement('div');
messageDiv.className = 'message';
const userSpan = document.createElement('span');
userSpan.className = 'message-user';
userSpan.textContent = `${userName}: `;
const textSpan = document.createElement('span');
textSpan.className = 'message-text';
textSpan.textContent = message;
messageDiv.appendChild(userSpan);
messageDiv.appendChild(textSpan);
messagesContainer.appendChild(messageDiv);
// Auto-scroll to the bottom
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
// Add a system message
function addSystemMessage(message) {
const messagesContainer = document.getElementById('chat-messages');
const messageDiv = document.createElement('div');
messageDiv.className = 'message';
messageDiv.style.color = '#8cf';
messageDiv.style.fontStyle = 'italic';
messageDiv.textContent = message;
messagesContainer.appendChild(messageDiv);
messagesContainer.scrollTop = messagesContainer.scrollHeight;
}
// Handle parameter change events from other users
function handleParameterChange(paramId, value, userName) {
const inputElement = document.getElementById(paramId);
if (inputElement) {
inputElement.value = value;
// Update the state accordingly
if (paramId === 'num-qubits') {
state.qubits = value;
drawCircuit();
drawHistogram();
drawEvolution();
} else if (paramId === 'num-shots') {
state.shots = value;
drawHistogram();
} else if (paramId === 'time-const') {
state.environmentParams.t = value;
drawEnvironment();
} else if (paramId === 'space-scale') {
state.environmentParams.s = value;
drawEnvironment();
} else if (paramId === 'mass-value') {
state.environmentParams.m = value;
drawEnvironment();
} else if (paramId === 'dimension-num') {
state.environmentParams.d = value;
drawEnvironment();
}
addSystemMessage(`${userName} changed ${paramId} to ${value}`);
}
}
// Handle run circuit events from other users
function handleRunCircuit(userName) {
addSystemMessage(`${userName} ran the quantum circuit`);
}
// Handle update environment events from other users
function handleUpdateEnv(userName) {
addSystemMessage(`${userName} updated the environment`);
}
// Handle run analysis events from other users
function handleRunAnalysis(userName) {
addSystemMessage(`${userName} ran a full analysis`);
}
// Modify the initialize function to include multiplayer
function initialize() {
// Set up input event handlers
document.getElementById('num-qubits').addEventListener('change', function(e) {
state.qubits = parseInt(e.target.value);
drawCircuit();
drawHistogram();
drawEvolution();
});
document.getElementById('num-shots').addEventListener('change', function(e) {
state.shots = parseInt(e.target.value);
drawHistogram();
});
document.getElementById('time-const').addEventListener('change', function(e) {
state.environmentParams.t = parseInt(e.target.value);
drawEnvironment();
});
document.getElementById('space-scale').addEventListener('change', function(e) {
state.environmentParams.s = parseInt(e.target.value);
drawEnvironment();
});
document.getElementById('mass-value').addEventListener('change', function(e) {
state.environmentParams.m = parseInt(e.target.value);
drawEnvironment();
});
document.getElementById('dimension-num').addEventListener('change', function(e) {
state.environmentParams.d = parseInt(e.target.value);
drawEnvironment();
});
// Set up button event handlers
document.getElementById('run-circuit').addEventListener('click', function() {
// Simulate running circuit
drawCircuit();
setTimeout(() => {
drawHistogram();
drawEvolution();
}, 500);
});
document.getElementById('update-env').addEventListener('click', function() {
// Simulate updating environment
drawEnvironment();
setTimeout(() => {
drawEvolution();
}, 500);
});
document.getElementById('run-analysis').addEventListener('click', function() {
// Simulate full analysis
drawCircuit();
setTimeout(() => {
drawEnvironment();
setTimeout(() => {
drawHistogram();
setTimeout(() => {
drawEvolution();
}, 300);
}, 300);
}, 300);
});
// Initial draw
drawCircuit();
drawEnvironment();
drawHistogram();
drawEvolution();
// Animation loop for evolution visualization
function animate() {
drawEvolution();
requestAnimationFrame(animate);
}
animate();
// Initialize multiplayer functionality
initMultiplayer();
}
// Handle window resize
window.addEventListener('resize', function() {
for (const canvas of Object.values(canvases)) {
canvas.width = canvas.clientWidth;
canvas.height = canvas.clientHeight;
}
drawCircuit();
drawEnvironment();
drawHistogram();
drawEvolution();
});
// Start the simulation
initialize();
</script>
</body>
</html>