Entangled Exhibition – Kimi Widget

<!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>

Posted

in

by

Tags: