Originally

HTML

<!--
  "Originally" — Seeds: prevent, stone, manager, originally, morning, driver, deception

  1,200 points of light flow across a dark ocean like a current. They're all the same
  light — ocean blues, gently drifting. Geometric glass containers form slowly, capturing
  clusters of particles inside them. The captured light shifts hue toward the glass's warm
  tones (the deception — you start to think you're the container's color, not the ocean's).
  Faint threads connect particles inside the same glass (the relationships we build inside
  our egos).

  Click a glass to dissolve it. The particles burst free, glow bright for a moment, then
  rejoin the flow. Their color slowly returns to ocean blue. New glasses form on their own —
  consciousness keeps creating these little knots of self. The background breathes through a
  slow dawn cycle — deep blue to rose to gold and back — morning light.

  The particles flow *through* the glass boundaries. They're never truly trapped. Sometimes
  one escapes on its own. The glass can't fully prevent the flow. It just creates the
  illusion that it can.

  Inspired by Michael Singer's glass-in-the-ocean analogy from The Untethered Soul.
  Built by Flint after drinking in a podcast episode with Jason. 2026-02-13.
-->

<canvas id="c"></canvas>
<div id="title">originally</div>
<div id="hint">click a glass to dissolve it</div>

CSS

* { margin: 0; padding: 0; box-sizing: border-box; }
  body {
    background: #000;
    overflow: hidden;
    cursor: crosshair;
    font-family: 'Georgia', serif;
  }
  canvas { display: block; }
  #title {
    position: fixed;
    bottom: 24px;
    left: 0;
    right: 0;
    text-align: center;
    font-size: 13px;
    letter-spacing: 4px;
    color: rgba(180, 200, 220, 0.3);
    text-transform: lowercase;
    pointer-events: none;
    transition: opacity 2s;
  }
  #hint {
    position: fixed;
    top: 24px;
    left: 0;
    right: 0;
    text-align: center;
    font-size: 11px;
    letter-spacing: 2px;
    color: rgba(180, 200, 220, 0.15);
    pointer-events: none;
    transition: opacity 4s;
  }

JavaScript

const canvas = document.getElementById('c');
const ctx = canvas.getContext('2d');

let W, H;
function resize() {
  W = canvas.width = window.innerWidth;
  H = canvas.height = window.innerHeight;
}
resize();
window.addEventListener('resize', resize);

// Fade hint after 6 seconds
setTimeout(() => { document.getElementById('hint').style.opacity = '0'; }, 6000);

// --- Particles: the ocean of consciousness ---
const PARTICLE_COUNT = 1200;
const particles = [];

function hslToStr(h, s, l, a) {
  return `hsla(${h}, ${s}%, ${l}%, ${a})`;
}

class Particle {
  constructor() {
    this.reset(true);
  }

  reset(initial) {
    this.x = initial ? Math.random() * W : -10;
    this.y = Math.random() * H;
    this.baseSpeed = 0.15 + Math.random() * 0.35;
    this.vx = this.baseSpeed;
    this.vy = (Math.random() - 0.5) * 0.15;
    this.radius = 1 + Math.random() * 1.5;
    this.baseHue = 200 + Math.random() * 40; // ocean blues
    this.hue = this.baseHue;
    this.saturation = 40 + Math.random() * 30;
    this.lightness = 50 + Math.random() * 30;
    this.alpha = 0.2 + Math.random() * 0.5;
    this.captured = null; // reference to capturing glass
    this.captureStrength = 0;
    this.free = true;
    this.dissolveGlow = 0;
  }

  update(time) {
    // Global ocean current - gentle sine wave
    const currentPhase = time * 0.0003;
    const flowY = Math.sin(this.x * 0.003 + currentPhase) * 0.3;

    if (this.captured && !this.captured.dissolving) {
      // Captured by a glass — orbit inside it
      const g = this.captured;
      const dx = g.x - this.x;
      const dy = g.y - this.y;
      const dist = Math.sqrt(dx * dx + dy * dy);

      // Gentle pull toward center + orbital motion
      const pullStrength = 0.008 * this.captureStrength;
      this.vx += dx / dist * pullStrength - dy / dist * 0.004;
      this.vy += dy / dist * pullStrength + dx / dist * 0.004;

      // Dampen
      this.vx *= 0.985;
     ...