<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Entangled Exhibition — Quantum Art Installation</title>
<style>
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Helvetica, Arial, sans-serif;
background: #0a0a0f;
color: #e2e8f0;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
padding: 24px;
}
.qe-widget {
width: 100%;
max-width: 800px;
background: #13131f;
border: 1px solid #1e1e2e;
border-radius: 16px;
padding: 28px;
box-shadow: 0 0 60px rgba(139, 92, 246, 0.06), 0 20px 60px rgba(0,0,0,0.4);
}
.qe-header {
font-size: 20px;
font-weight: 600;
color: #f8fafc;
margin-bottom: 24px;
display: flex;
align-items: center;
gap: 12px;
letter-spacing: -0.01em;
}
.qe-pulse {
width: 10px;
height: 10px;
border-radius: 50%;
background: #10b981;
box-shadow: 0 0 12px #10b981;
animation: qe-pulse 2.2s infinite;
flex-shrink: 0;
}
@keyframes qe-pulse {
0%, 100% { opacity: 1; transform: scale(1); }
50% { opacity: 0.3; transform: scale(0.85); }
}
.qe-nodes {
display: flex;
gap: 16px;
margin-bottom: 20px;
}
@media (max-width: 640px) {
.qe-nodes { flex-direction: column; }
}
.qe-node {
flex: 1;
border: 1px solid #1e1e2e;
border-radius: 12px;
padding: 16px;
background: #0f0f18;
transition: border-color 0.25s ease, box-shadow 0.25s ease;
}
.qe-node.measured {
border-color: #8b5cf6;
box-shadow: 0 0 20px rgba(139, 92, 246, 0.08);
}
.qe-node-label {
font-size: 11px;
font-weight: 600;
color: #64748b;
text-transform: uppercase;
letter-spacing: 0.08em;
margin-bottom: 4px;
}
.qe-node-title {
font-size: 15px;
font-weight: 600;
color: #f1f5f9;
margin-bottom: 8px;
}
.qe-node-status {
font-size: 13px;
color: #94a3b8;
margin-bottom: 12px;
min-height: 20px;
font-style: italic;
}
.qe-canvas-wrap {
width: 100%;
height: 220px;
border-radius: 10px;
overflow: hidden;
background: #0a0a12;
position: relative;
border: 1px solid #1a1a28;
}
.qe-canvas-wrap canvas {
display: block;
width: 100%;
height: 100%;
}
.qe-infobar {
display: flex;
flex-wrap: wrap;
gap: 10px 18px;
padding: 14px 16px;
border-radius: 10px;
background: #0f0f18;
border: 1px solid #1e1e2e;
font-size: 13px;
color: #94a3b8;
margin-bottom: 16px;
align-items: center;
}
.qe-infobar .qe-metric {
font-weight: 600;
color: #f8fafc;
font-variant-numeric: tabular-nums;
}
.qe-divider {
width: 1px;
height: 16px;
background: #1e1e2e;
}
.qe-controls {
display: flex;
gap: 10px;
margin-bottom: 16px;
flex-wrap: wrap;
}
.qe-btn {
padding: 10px 18px;
border: 1px solid #2e2e3e;
border-radius: 10px;
background: #1a1a28;
color: #e2e8f0;
font-size: 14px;
font-weight: 500;
cursor: pointer;
transition: all 0.2s ease;
font-family: inherit;
line-height: 1.4;
}
.qe-btn:hover {
background: #252536;
border-color: #3e3e52;
transform: translateY(-1px);
}
.qe-btn:active {
transform: translateY(0) scale(0.98);
}
.qe-btn.primary {
border-color: #8b5cf6;
background: #8b5cf6;
color: #ffffff;
box-shadow: 0 4px 16px rgba(139, 92, 246, 0.25);
}
.qe-btn.primary:hover {
background: #7c3aed;
border-color: #7c3aed;
box-shadow: 0 6px 20px rgba(139, 92, 246, 0.35);
}
.qe-legend {
display: flex;
gap: 20px;
font-size: 12px;
color: #64748b;
margin-top: 8px;
}
.qe-legend-item {
display: flex;
align-items: center;
gap: 8px;
}
.qe-swatch {
width: 10px;
height: 10px;
border-radius: 50%;
}
.qe-swatch-us { background: #06b6d4; box-shadow: 0 0 8px rgba(6, 182, 212, 0.4); }
.qe-swatch-eu { background: #f59e0b; box-shadow: 0 0 8px rgba(245, 158, 11, 0.4); }
.qe-swatch-field { background: #475569; }
.qe-footer {
margin-top: 20px;
padding-top: 16px;
border-top: 1px solid #1e1e2e;
font-size: 12px;
color: #475569;
text-align: center;
line-height: 1.6;
}
.qe-footer em {
color: #64748b;
font-style: italic;
}
</style>
<base target="_blank">
</head>
<body>
<div class="qe-widget" id="qe-widget">
<div class="qe-header">
<div class="qe-pulse"></div>
entangled exhibition prototype
</div>
<div class="qe-nodes">
<div class="qe-node" id="qe-node-us">
<div class="qe-node-label">node A</div>
<div class="qe-node-title">University Hall, Indiana</div>
<div class="qe-node-status" id="qe-status-us">awaiting measurement</div>
<div class="qe-canvas-wrap">
<canvas id="qe-canvas-us"></canvas>
</div>
</div>
<div class="qe-node" id="qe-node-eu">
<div class="qe-node-label">node B</div>
<div class="qe-node-title">University Hall, Leiden</div>
<div class="qe-node-status" id="qe-status-eu">awaiting measurement</div>
<div class="qe-canvas-wrap">
<canvas id="qe-canvas-eu"></canvas>
</div>
</div>
</div>
<div class="qe-infobar">
<span>correlation coefficient</span>
<span class="qe-metric" id="qe-corr">—</span>
<div class="qe-divider"></div>
<span>shared state</span>
<span class="qe-metric" id="qe-state">superposition</span>
<div class="qe-divider"></div>
<span>latency</span>
<span class="qe-metric">~142 ms</span>
</div>
<div class="qe-controls">
<button class="qe-btn primary" onclick="qeMeasure('us')">measure node A</button>
<button class="qe-btn primary" onclick="qeMeasure('eu')">measure node B</button>
<button class="qe-btn" onclick="qeReset()">reset entanglement</button>
<button class="qe-btn" onclick="qeToggleAuto()">auto-cascade</button>
</div>
<div class="qe-legend">
<div class="qe-legend-item">
<div class="qe-swatch qe-swatch-us"></div>
<span>node A spin</span>
</div>
<div class="qe-legend-item">
<div class="qe-swatch qe-swatch-eu"></div>
<span>node B spin</span>
</div>
<div class="qe-legend-item">
<div class="qe-swatch qe-swatch-field"></div>
<span>entanglement field</span>
</div>
</div>
<div class="qe-footer">
<em>"Two discrete physical spaces, one artwork. The correlation is a property of the system, not of the distance between them."</em>
</div>
</div>
<script>
(function() {
var canvasUS = document.getElementById("qe-canvas-us");
var canvasEU = document.getElementById("qe-canvas-eu");
var ctxUS = canvasUS.getContext("2d");
var ctxEU = canvasEU.getContext("2d");
var width, height;
function resize() {
var rect = canvasUS.parentElement.getBoundingClientRect();
width = rect.width;
height = rect.height;
var dpr = window.devicePixelRatio || 1;
canvasUS.width = width * dpr;
canvasUS.height = height * dpr;
canvasEU.width = width * dpr;
canvasEU.height = height * dpr;
ctxUS.setTransform(dpr, 0, 0, dpr, 0, 0);
ctxEU.setTransform(dpr, 0, 0, dpr, 0, 0);
}
resize();
window.addEventListener("resize", resize);
var state = {
phase: 0,
usMeasured: false,
euMeasured: false,
usSpin: null,
euSpin: null,
entangled: true,
auto: false,
autoTimer: null
};
var colors = {
us: "#06b6d4",
eu: "#f59e0b",
field: "#475569",
bg: "#0a0a12",
textPrimary: "#f8fafc",
textSecondary: "#94a3b8"
};
function drawNode(ctx, node, t) {
ctx.clearRect(0, 0, width, height);
var cx = width / 2;
var cy = height / 2;
var baseR = Math.min(width, height) * 0.32;
if (state.entangled && !state.usMeasured && !state.euMeasured) {
ctx.save();
ctx.globalAlpha = 0.10;
ctx.fillStyle = colors.field;
for (var i = 0; i < 14; i++) {
var r = baseR * (0.25 + i * 0.07);
ctx.beginPath();
ctx.arc(cx, cy, r + Math.sin(t * 0.0018 + i * 0.7) * 5, 0, Math.PI * 2);
ctx.fill();
}
ctx.restore();
}
if (state.entangled) {
ctx.save();
ctx.strokeStyle = colors.field;
ctx.lineWidth = 1;
ctx.setLineDash([5, 7]);
ctx.globalAlpha = 0.30 + Math.sin(t * 0.0025) * 0.15;
ctx.beginPath();
ctx.moveTo(cx - baseR * 0.55, cy);
ctx.lineTo(cx + baseR * 0.55, cy);
ctx.stroke();
ctx.restore();
}
var spin = node === "us" ? state.usSpin : state.euSpin;
var measured = node === "us" ? state.usMeasured : state.euMeasured;
var color = node === "us" ? colors.us : colors.eu;
if (!measured) {
ctx.save();
ctx.strokeStyle = color;
ctx.lineWidth = 2;
ctx.globalAlpha = 0.22;
ctx.beginPath();
ctx.ellipse(cx, cy, baseR * 0.7, baseR * 0.28, t * 0.0008, 0, Math.PI * 2);
ctx.stroke();
ctx.beginPath();
ctx.ellipse(cx, cy, baseR * 0.28, baseR * 0.7, -t * 0.0008, 0, Math.PI * 2);
ctx.stroke();
ctx.restore();
ctx.save();
ctx.fillStyle = color;
ctx.globalAlpha = 0.50 + Math.sin(t * 0.004) * 0.18;
ctx.shadowColor = color;
ctx.shadowBlur = 12;
ctx.beginPath();
ctx.arc(cx, cy, 5, 0, Math.PI * 2);
ctx.fill();
ctx.restore();
} else {
var angle = spin === "up" ? -Math.PI / 2 : Math.PI / 2;
var arrowLen = baseR * 0.48;
ctx.save();
ctx.strokeStyle = color;
ctx.lineWidth = 3;
ctx.lineCap = "round";
ctx.shadowColor = color;
ctx.shadowBlur = 10;
ctx.beginPath();
ctx.moveTo(cx, cy);
ctx.lineTo(cx + Math.cos(angle) * arrowLen, cy + Math.sin(angle) * arrowLen);
ctx.stroke();
ctx.shadowBlur = 0;
ctx.beginPath();
ctx.moveTo(cx + Math.cos(angle) * arrowLen, cy + Math.sin(angle) * arrowLen);
ctx.lineTo(cx + Math.cos(angle - 0.3) * (arrowLen - 10), cy + Math.sin(angle - 0.3) * (arrowLen - 10));
ctx.lineTo(cx + Math.cos(angle + 0.3) * (arrowLen - 10), cy + Math.sin(angle + 0.3) * (arrowLen - 10));
ctx.closePath();
ctx.fillStyle = color;
ctx.fill();
ctx.restore();
ctx.save();
ctx.font = "500 13px -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica, Arial, sans-serif";
ctx.fillStyle = colors.textPrimary;
ctx.textAlign = "center";
ctx.fillText(spin === "up" ? "spin up (↑)" : "spin down (↓)", cx, cy + baseR * 0.82);
ctx.restore();
}
if (measured) {
ctx.save();
ctx.strokeStyle = color;
ctx.lineWidth = 1.5;
ctx.globalAlpha = 0.15;
ctx.beginPath();
ctx.arc(cx, cy, baseR * 0.82, 0, Math.PI * 2);
ctx.stroke();
ctx.restore();
}
}
function updateUI() {
var corr = (!state.usMeasured || !state.euMeasured) ? "—" : (state.usSpin !== state.euSpin ? "-1.00" : "+1.00");
document.getElementById("qe-corr").textContent = corr;
document.getElementById("qe-state").textContent =
!state.usMeasured && !state.euMeasured ? "superposition" :
state.usMeasured && state.euMeasured ? "collapsed (correlated)" :
"partially measured";
document.getElementById("qe-status-us").textContent = state.usMeasured ? "measured: " + state.usSpin : "awaiting measurement";
document.getElementById("qe-status-eu").textContent = state.euMeasured ? "measured: " + state.euSpin : "awaiting measurement";
document.getElementById("qe-node-us").classList.toggle("measured", state.usMeasured);
document.getElementById("qe-node-eu").classList.toggle("measured", state.euMeasured);
}
window.qeMeasure = function(node) {
if (node === "us" && state.usMeasured) return;
if (node === "eu" && state.euMeasured) return;
var spin = Math.random() < 0.5 ? "up" : "down";
if (node === "us") {
state.usSpin = spin;
state.usMeasured = true;
if (state.entangled) {
state.euSpin = spin === "up" ? "down" : "up";
state.euMeasured = true;
}
} else {
state.euSpin = spin;
state.euMeasured = true;
if (state.entangled) {
state.usSpin = spin === "up" ? "down" : "up";
state.usMeasured = true;
}
}
updateUI();
};
window.qeReset = function() {
state.usMeasured = false;
state.euMeasured = false;
state.usSpin = null;
state.euSpin = null;
state.entangled = true;
if (state.autoTimer) clearTimeout(state.autoTimer);
state.auto = false;
updateUI();
};
window.qeToggleAuto = function() {
state.auto = !state.auto;
if (state.auto) autoStep();
else if (state.autoTimer) clearTimeout(state.autoTimer);
};
function autoStep() {
if (!state.auto) return;
if (!state.usMeasured) {
window.qeMeasure("us");
state.autoTimer = setTimeout(autoStep, 2200);
} else if (!state.euMeasured) {
window.qeMeasure("eu");
state.autoTimer = setTimeout(function() {
window.qeReset();
state.autoTimer = setTimeout(autoStep, 1600);
}, 3200);
} else {
state.autoTimer = setTimeout(function() {
window.qeReset();
state.autoTimer = setTimeout(autoStep, 1600);
}, 2200);
}
}
function loop(t) {
state.phase = t;
drawNode(ctxUS, "us", t);
drawNode(ctxEU, "eu", t);
requestAnimationFrame(loop);
}
updateUI();
requestAnimationFrame(loop);
})();
</script>
</body>
</html>
Entangled Exhibition – Kimi Widget
by
Tags: