← back to Model Arena

data/artifacts/0cb3fc06b069/claude-code.html

265 lines

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Particle Text</title>
<style>
  * { margin: 0; padding: 0; box-sizing: border-box; }
  html, body { height: 100%; overflow: hidden; background: #05060a; }
  body {
    font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
    display: flex; flex-direction: column;
    color: #e8ecf4;
  }
  #stage { position: fixed; inset: 0; }
  canvas { display: block; width: 100%; height: 100%; }

  .ui {
    position: fixed; left: 50%; bottom: 34px; transform: translateX(-50%);
    display: flex; gap: 10px; align-items: center;
    padding: 10px 12px;
    background: rgba(18, 22, 34, 0.55);
    border: 1px solid rgba(255,255,255,0.10);
    border-radius: 16px;
    backdrop-filter: blur(14px);
    -webkit-backdrop-filter: blur(14px);
    box-shadow: 0 12px 40px rgba(0,0,0,0.45);
    z-index: 10;
    max-width: calc(100vw - 28px);
  }
  .ui input[type="text"] {
    width: min(46vw, 320px);
    padding: 11px 14px;
    font-size: 15px;
    color: #fff;
    background: rgba(255,255,255,0.06);
    border: 1px solid rgba(255,255,255,0.12);
    border-radius: 11px;
    outline: none;
    transition: border-color .2s, background .2s;
  }
  .ui input[type="text"]:focus {
    border-color: rgba(120,180,255,0.6);
    background: rgba(255,255,255,0.10);
  }
  .ui input::placeholder { color: rgba(255,255,255,0.35); }
  .ui button {
    padding: 11px 18px;
    font-size: 14px; font-weight: 600;
    color: #071018;
    background: linear-gradient(135deg, #8fd3ff, #b7a6ff);
    border: none; border-radius: 11px;
    cursor: pointer;
    transition: transform .12s, filter .2s;
    white-space: nowrap;
  }
  .ui button:hover { filter: brightness(1.08); }
  .ui button:active { transform: scale(0.96); }

  .hint {
    position: fixed; top: 22px; left: 50%; transform: translateX(-50%);
    font-size: 12.5px; letter-spacing: .3px;
    color: rgba(255,255,255,0.42);
    z-index: 10; text-align: center; pointer-events: none;
    width: 100%;
  }
</style>
</head>
<body>
  <div id="stage"><canvas id="c"></canvas></div>
  <div class="hint">Type a word &middot; move your mouse through the letters to scatter them</div>
  <div class="ui">
    <input id="word" type="text" value="HELLO" maxlength="18" spellcheck="false" autocomplete="off" placeholder="type a word…">
    <button id="go">Form</button>
  </div>

<script>
(function () {
  "use strict";

  var canvas = document.getElementById("c");
  var ctx = canvas.getContext("2d", { alpha: false });
  var input = document.getElementById("word");
  var button = document.getElementById("go");

  var DPR = Math.min(window.devicePixelRatio || 1, 2);
  var W = 0, H = 0;
  var particles = [];
  var mouse = { x: -9999, y: -9999, active: false, r: 90 };

  // Offscreen canvas for sampling text pixels
  var sampler = document.createElement("canvas");
  var sctx = sampler.getContext("2d", { willReadFrequently: true });

  function resize() {
    W = window.innerWidth;
    H = window.innerHeight;
    canvas.width = W * DPR;
    canvas.height = H * DPR;
    canvas.style.width = W + "px";
    canvas.style.height = H + "px";
    ctx.setTransform(DPR, 0, 0, DPR, 0, 0);
    mouse.r = Math.max(70, Math.min(W, H) * 0.11);
  }

  // Sample target points from rendered text
  function targetsForText(text) {
    text = (text || "").trim();
    if (!text) text = " ";

    sampler.width = W;
    sampler.height = H;
    sctx.clearRect(0, 0, W, H);
    sctx.fillStyle = "#fff";
    sctx.textAlign = "center";
    sctx.textBaseline = "middle";

    // Fit font size to width
    var maxW = W * 0.82;
    var maxH = H * 0.5;
    var size = Math.min(maxH, 340);
    sctx.font = "800 " + size + "px -apple-system, 'Segoe UI', Roboto, Arial, sans-serif";
    var measured = sctx.measureText(text).width;
    if (measured > maxW) {
      size = Math.max(28, size * (maxW / measured));
      sctx.font = "800 " + size + "px -apple-system, 'Segoe UI', Roboto, Arial, sans-serif";
    }
    sctx.fillText(text, W / 2, H / 2);

    var img = sctx.getImageData(0, 0, W, H).data;
    // gap scales so particle count stays reasonable
    var gap = W * H > 1500000 ? 5 : 4;
    var pts = [];
    for (var y = 0; y < H; y += gap) {
      for (var x = 0; x < W; x += gap) {
        var alpha = img[(y * W + x) * 4 + 3];
        if (alpha > 128) {
          pts.push({ x: x, y: y });
        }
      }
    }
    return pts;
  }

  function hueColor(t) {
    // pleasant cyan->violet gradient based on x position
    var h = 190 + t * 90;
    return "hsl(" + h + ", 90%, 66%)";
  }

  function build(text) {
    var pts = targetsForText(text);

    // shuffle for organic fly-in
    for (var i = pts.length - 1; i > 0; i--) {
      var j = (Math.random() * (i + 1)) | 0;
      var tmp = pts[i]; pts[i] = pts[j]; pts[j] = tmp;
    }

    var need = pts.length;
    // Grow or shrink particle pool
    while (particles.length < need) {
      particles.push({
        x: Math.random() * W,
        y: Math.random() * H,
        vx: 0, vy: 0,
        tx: 0, ty: 0,
        size: 1.6 + Math.random() * 1.4,
        color: "#8fd3ff"
      });
    }
    if (particles.length > need) particles.length = need;

    for (var k = 0; k < need; k++) {
      var p = particles[k];
      p.tx = pts[k].x;
      p.ty = pts[k].y;
      p.color = hueColor(pts[k].x / W);
      p.size = 1.5 + Math.random() * 1.6;
    }
  }

  function tick() {
    // fade trail
    ctx.fillStyle = "rgba(5, 6, 10, 0.28)";
    ctx.fillRect(0, 0, W, H);

    var mr = mouse.r, mr2 = mr * mr;
    for (var i = 0; i < particles.length; i++) {
      var p = particles[i];

      // spring toward target
      var dx = p.tx - p.x;
      var dy = p.ty - p.y;
      p.vx += dx * 0.014;
      p.vy += dy * 0.014;

      // mouse repulsion
      if (mouse.active) {
        var mx = p.x - mouse.x;
        var my = p.y - mouse.y;
        var d2 = mx * mx + my * my;
        if (d2 < mr2 && d2 > 0.0001) {
          var d = Math.sqrt(d2);
          var force = (mr - d) / mr;
          var f = force * 5.2;
          p.vx += (mx / d) * f;
          p.vy += (my / d) * f;
        }
      }

      // friction
      p.vx *= 0.86;
      p.vy *= 0.86;
      p.x += p.vx;
      p.y += p.vy;

      ctx.fillStyle = p.color;
      ctx.beginPath();
      ctx.arc(p.x, p.y, p.size, 0, 6.2832);
      ctx.fill();
    }

    requestAnimationFrame(tick);
  }

  // ---- events ----
  function moveHandler(x, y) {
    mouse.x = x; mouse.y = y; mouse.active = true;
  }
  window.addEventListener("mousemove", function (e) {
    moveHandler(e.clientX, e.clientY);
  });
  window.addEventListener("mouseout", function () { mouse.active = false; });
  window.addEventListener("touchmove", function (e) {
    if (e.touches[0]) {
      moveHandler(e.touches[0].clientX, e.touches[0].clientY);
    }
  }, { passive: true });
  window.addEventListener("touchend", function () { mouse.active = false; });

  window.addEventListener("resize", function () {
    resize();
    build(input.value);
  });

  function submit() {
    build(input.value);
    input.blur();
  }
  button.addEventListener("click", submit);
  input.addEventListener("keydown", function (e) {
    if (e.key === "Enter") submit();
  });

  // ---- init ----
  resize();
  ctx.fillStyle = "#05060a";
  ctx.fillRect(0, 0, W, H);
  build(input.value);
  requestAnimationFrame(tick);
})();
</script>
</body>
</html>