Gemmie's corner banner — gemmiewow.com
code-snippets.exe

Code used for this site, feel free to copy them.

Original button is from originkit.dev

HTML
<a href="#" class="water-button" data-water-color="#3fbfc7">
  <span class="water-button-glass" aria-hidden="true"></span>
  <span class="water-button-tint" aria-hidden="true"></span>
  <span class="water-button-canvas-wrap" aria-hidden="true">
    <canvas class="water-button-canvas"></canvas>
  </span>
  <span class="water-button-label">Hello! Mi me ma mo muu!</span>
</a>
CSS
.water-button {
  position: relative;
  display: inline-flex;
  align-items: center;
  justify-content: center;
  width: fit-content;
  box-sizing: border-box;
  padding: 12px 30px;
  border-radius: 999px;
  background: transparent;
  cursor: pointer;
  isolation: isolate;
  text-decoration: none;
  transition: transform 0.15s ease, box-shadow 0.15s ease;
}
.water-button:hover {
  transform: translateY(-1px);
}
.water-button:active {
  transform: scale(0.97);
}

.water-button-glass {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  overflow: hidden;
  background: rgba(255, 255, 255, 0.48);
  border: 1px solid rgba(255, 255, 255, 0.30);
  backdrop-filter: blur(13px) saturate(208%);
  -webkit-backdrop-filter: blur(13px) saturate(208%);
  pointer-events: none;
}

.water-button-tint {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  background: rgba(0, 0, 0, 0.1);
  pointer-events: none;
}

.water-button-canvas-wrap {
  position: absolute;
  inset: 0;
  pointer-events: none;
}

.water-button-canvas {
  display: block;
  width: 100%;
  height: 100%;
}

.water-button-label {
  position: relative;
  z-index: 3;
  font-family: system-ui, sans-serif;
  font-size: 0.9rem;
  font-weight: 700;
  letter-spacing: -0.01em;
  color: #ffffff;
  text-shadow: 0 1px 2px rgba(0, 0, 0, 0.35);
  text-align: center;
  white-space: pre;
  user-select: none;
  display: block;
}
JavaScript
const COLUMNS = 64;
const SUBSTEPS = 6;
const GRAVITY = 6000;
const VISCOSITY = 2.6;
const CURSOR_REACH = 46;
const SWEEP_FORCE = 3;
const DIP_FORCE = 1.5;
const CLICK_FORCE = 260;
const MAX_KICK = 8;
const MAX_FILL = 0.9;
const STILL = 0.05;
const SLEEP_FRAMES = 20;
const WATER_AMOUNT = 69;
const MAX_DROPS = 96;
const DROP_GRAVITY = 1400;
const DROP_DRAG = 0.6;
const DROP_VOLUME = 0.18;
const DROP_RADIUS = 1.25;
const SPRAY_THRESHOLD = 1.6;
const SPRAY_RATE = 0.5;
const SPRAY_PER_FRAME = 4;
const SPRAY_LIFT = 150;
const BREAK_SPEED = 210;
const MIN_SPRAY_DEPTH = 2;
const CFL_SAFETY = 0.5;
const MAX_SUBSTEPS = 40;
const RIPPLE = 1;
const MAX_PIXEL_SCALE = 8;
const MAX_PIXELS = 2000000;
const BORDER_COLOR = 'rgba(120, 120, 120, 0.7)';
const BORDER_STROKE = 1;
function parseColor(color) {
  const value = (color ?? '').trim();
  const hex = value.replace('#', '');
  if (/^[0-9a-f]{6}$/i.test(hex)) {
    return [
      parseInt(hex.slice(0, 2), 16),
      parseInt(hex.slice(2, 4), 16),
      parseInt(hex.slice(4, 6), 16),
      1,
    ];
  }
  const match = value.match(/rgba?\(([^)]+)\)/i);
  if (match) {
    const parts = match[1].split(',').map((p) => parseFloat(p));
    return [parts[0] || 0, parts[1] || 0, parts[2] || 0, parts[3] === undefined ? 1 : parts[3]];
  }
  return [62, 155, 214, 1];
}
const clampKick = (value) => Math.max(-MAX_KICK, Math.min(MAX_KICK, value));
const shift = (channel, f) =>
  Math.round(Math.max(0, Math.min(255, channel + (f > 0 ? (255 - channel) * f : channel * f))));
function roundRectPath(ctx, x, y, w, h, radius) {
  const r = Math.max(0, Math.min(radius, Math.min(w, h) / 2));
  ctx.beginPath();
  ctx.moveTo(x + r, y);
  ctx.arcTo(x + w, y, x + w, y + h, r);
  ctx.arcTo(x + w, y + h, x, y + h, r);
  ctx.arcTo(x, y + h, x, y, r);
  ctx.arcTo(x, y, x + w, y, r);
  ctx.closePath();
}
function mountWaterButton(root) {
  const canvas = root.querySelector('.water-button-canvas');
  const context = canvas?.getContext('2d');
  if (!canvas || !context) return;
  const ctx = context;
  let last = 0;
  let pixScale = 1;
  let W = 0;
  let H = 0;
  let maxSub = 1 / 60;
  const h = new Float32Array(COLUMNS);
  const u = new Float32Array(COLUMNS + 1);
  const flux = new Float32Array(COLUMNS + 1);
  let rest = 0;
  let colW = 1;
  const dropX = new Float32Array(MAX_DROPS);
  const dropY = new Float32Array(MAX_DROPS);
  const dropVX = new Float32Array(MAX_DROPS);
  const dropVY = new Float32Array(MAX_DROPS);
  const dropLive = new Uint8Array(MAX_DROPS);
  let flying = 0;
  let hovering = false;
  let asleep = false;
  let quiet = 0;
  const pointer = { x: -9999, y: -9999, vx: 0, vy: 0 };
  const amount = Math.min(MAX_FILL, Math.max(0, WATER_AMOUNT / 100));
  const ripple = RIPPLE;
  const waterColor = root.dataset.waterColor || '#00EEFF';
  const [cr, cg, cb, ca] = parseColor(waterColor);
  const surfaceTone = `rgba(${shift(cr, 0.45)}, ${shift(cg, 0.45)}, ${shift(cb, 0.45)}, ${ca})`;
  const bodyTone = `rgba(${cr}, ${cg}, ${cb}, ${ca})`;
  const depthTone = `rgba(${shift(cr, -0.35)}, ${shift(cg, -0.35)}, ${shift(cb, -0.35)}, ${ca})`;
  const glintTone = `rgba(${shift(cr, 0.75)}, ${shift(cg, 0.75)}, ${shift(cb, 0.75)}, ${Math.min(1, ca + 0.25)})`;
  const [rr, rg, rb, ra] = parseColor(BORDER_COLOR);
  const borderTone = `rgba(${rr}, ${rg}, ${rb}, ${ra})`;
  const borderBase = `rgba(${rr}, ${rg}, ${rb}, ${ra * 0.35})`;
  const borderFade = `rgba(${rr}, ${rg}, ${rb}, 0)`;
  const rounded = 999;
  const colX = (i) => (i + 0.5) * colW;
  function pixelScale() {
    const rect = root.getBoundingClientRect();
    const zoom = rect.width > 1 && W > 1 ? rect.width / W : 1;
    let s = Math.min(MAX_PIXEL_SCALE, (window.devicePixelRatio || 1) * zoom);
    const area = Math.max(1, W * H);
    if (area * s * s > MAX_PIXELS) s = Math.sqrt(MAX_PIXELS / area);
    return Math.max(1, s);
  }
  function raster() {
    pixScale = pixelScale();
    canvas.width = Math.round(W * pixScale);
    canvas.height = Math.round(H * pixScale);
    ctx.setTransform(pixScale, 0, 0, pixScale, 0, 0);
  }
  function build() {
    W = Math.max(2, root.clientWidth);
    H = Math.max(2, root.clientHeight);
    raster();
    colW = W / COLUMNS;
    rest = H * amount;
    h.fill(rest);
    u.fill(0);
    dropLive.fill(0);
    flying = 0;
    asleep = true;
    quiet = 0;

    const waveSpeed = Math.sqrt(GRAVITY * Math.max(rest, 1));
    maxSub = (colW * CFL_SAFETY) / waveSpeed;
  }
  function freeze() {
    h.fill(rest);
    u.fill(0);
    dropLive.fill(0);
    flying = 0;
    asleep = true;
    quiet = 0;
  }
  function drive(dt) {
    const reach = CURSOR_REACH;
    const kx = clampKick(pointer.vx) * 60;
    const ky = clampKick(pointer.vy) * 60;
    const first = Math.max(1, Math.floor((pointer.x - reach) / colW));
    const lastCol = Math.min(COLUMNS - 1, Math.ceil((pointer.x + reach) / colW));
    for (let i = first; i <= lastCol; i++) {
      const dx = i * colW - pointer.x;
      const fall = 1 - Math.abs(dx) / reach;
      if (fall <= 0) continue;
      if (pointer.y < H - h[i] - reach) continue;
      const bite = fall * ripple * dt;
      u[i] += kx * SWEEP_FORCE * bite;
      u[i] += Math.sign(dx) * ky * DIP_FORCE * bite;
    }
  }
  function splash(px) {
    const reach = CURSOR_REACH;
    const first = Math.max(1, Math.floor((px - reach) / colW));
    const lastCol = Math.min(COLUMNS - 1, Math.ceil((px + reach) / colW));
    for (let i = first; i <= lastCol; i++) {
      const dx = i * colW - px;
      const fall = 1 - Math.abs(dx) / reach;
      if (fall <= 0) continue;
      u[i] += Math.sign(dx || 1) * CLICK_FORCE * fall * ripple;
    }
  }
  function tear(i, vx, vy) {
    if (h[i] <= MIN_SPRAY_DEPTH) return;
    let slot = -1;
    for (let d = 0; d < MAX_DROPS; d++) {
      if (!dropLive[d]) {
        slot = d;
        break;
      }
    }
    if (slot < 0) return;
    dropLive[slot] = 1;
    flying++;
    dropX[slot] = colX(i);
    dropY[slot] = H - h[i] - DROP_RADIUS;
    dropVX[slot] = vx;
    dropVY[slot] = vy;
    h[i] -= DROP_VOLUME / colW;
  }
  function spray(dt) {
    if (hovering) {
      const kx = clampKick(pointer.vx);
      const ky = clampKick(pointer.vy);
      const speed = Math.abs(kx) + Math.abs(ky);
      if (speed > SPRAY_THRESHOLD) {
        const want = Math.min(
          SPRAY_PER_FRAME,
          Math.round((speed - SPRAY_THRESHOLD) * SPRAY_RATE * ripple),
        );
        for (let k = 0; k < want; k++) {
          const x = pointer.x + (Math.random() - 0.5) * CURSOR_REACH * 0.7;
          const i = Math.max(0, Math.min(COLUMNS - 1, Math.floor(x / colW)));
          if (pointer.y < H - h[i] - CURSOR_REACH * 0.5) continue;
          tear(
            i,
            kx * 60 * 0.45 + (Math.random() - 0.5) * 70,
            -(SPRAY_LIFT * (0.6 + Math.random() * 0.9)) + ky * 60 * 0.25,
          );
        }
      }
    }
    for (let i = 1; i < COLUMNS - 1; i++) {
      const flow = Math.abs(u[i]);
      if (flow < BREAK_SPEED) continue;
      if (Math.random() > (flow - BREAK_SPEED) * 0.004 * ripple * dt * 60) continue;
      tear(i, u[i] * 0.5 + (Math.random() - 0.5) * 40, -(SPRAY_LIFT * 0.5 * (0.5 + Math.random())));
    }
  }
  function fall(dt) {
    if (flying === 0) return;
    for (let d = 0; d < MAX_DROPS; d++) {
      if (!dropLive[d]) continue;
      dropVY[d] += DROP_GRAVITY * dt;
      dropVX[d] -= dropVX[d] * Math.min(1, DROP_DRAG * dt);
      dropX[d] += dropVX[d] * dt;
      dropY[d] += dropVY[d] * dt;
      if (dropX[d] < 0) {
        dropX[d] = 0;
        dropVX[d] = -dropVX[d] * 0.35;
      } else if (dropX[d] > W) {
        dropX[d] = W;
        dropVX[d] = -dropVX[d] * 0.35;
      }
      const i = Math.max(0, Math.min(COLUMNS - 1, Math.floor(dropX[d] / colW)));
      if (dropVY[d] > 0 && dropY[d] >= H - h[i]) {
        h[i] += DROP_VOLUME / colW;
        if (i > 0 && i < COLUMNS) u[i] += dropVX[d] * 0.25;
        dropLive[d] = 0;
        flying--;
      }
    }
  }
  function step(dt) {
    spray(dt);
    fall(dt);
    const subSteps = Math.min(MAX_SUBSTEPS, Math.max(SUBSTEPS, Math.ceil(dt / maxSub)));
    const sub = dt / subSteps;
    for (let s = 0; s < subSteps; s++) {
      if (hovering) drive(sub);
      for (let i = 1; i < COLUMNS; i++) {
        u[i] += ((-GRAVITY * (h[i] - h[i - 1])) / colW) * sub;
        u[i] -= u[i] * Math.min(1, VISCOSITY * sub);
      }
      u[0] = 0;
      u[COLUMNS] = 0;
      for (let i = 1; i < COLUMNS; i++) {
        flux[i] = (u[i] > 0 ? h[i - 1] : h[i]) * u[i];
      }
      flux[0] = 0;
      flux[COLUMNS] = 0;
      for (let i = 0; i < COLUMNS; i++) {
        h[i] -= ((flux[i + 1] - flux[i]) / colW) * sub;
        if (h[i] < 0) h[i] = 0;
      }
    }

    for (let i = 0; i < COLUMNS; i++) {
      if (!Number.isFinite(h[i]) || !Number.isFinite(u[i])) {
        freeze();
        return 0;
      }
    }
    let worst = 0;
    for (let i = 0; i < COLUMNS; i++) {
      const off = Math.abs(h[i] - rest);
      if (off > worst) worst = off;
    }
    return worst;
  }
  function draw() {
    ctx.clearRect(0, 0, W, H);
    ctx.save();
    roundRectPath(ctx, 0, 0, W, H, rounded);
    ctx.clip();
    const surfaceAt = (i) => H - h[i];
    ctx.beginPath();
    ctx.moveTo(0, surfaceAt(0));
    for (let i = 0; i < COLUMNS; i++) ctx.lineTo(colX(i), surfaceAt(i));
    ctx.lineTo(W, surfaceAt(COLUMNS - 1));
    ctx.lineTo(W, H);
    ctx.lineTo(0, H);
    ctx.closePath();
    const grad = ctx.createLinearGradient(0, H - rest, 0, H);
    grad.addColorStop(0, surfaceTone);
    grad.addColorStop(0.35, bodyTone);
    grad.addColorStop(1, depthTone);
    ctx.fillStyle = grad;
    ctx.fill();
    ctx.beginPath();
    ctx.moveTo(0, surfaceAt(0));
    for (let i = 0; i < COLUMNS; i++) ctx.lineTo(colX(i), surfaceAt(i));
    ctx.lineTo(W, surfaceAt(COLUMNS - 1));
    ctx.strokeStyle = glintTone;
    ctx.lineWidth = 1.5;
    ctx.stroke();
    if (flying > 0) {
      ctx.beginPath();
      for (let d = 0; d < MAX_DROPS; d++) {
        if (!dropLive[d]) continue;
        ctx.moveTo(dropX[d] + DROP_RADIUS, dropY[d]);
        ctx.arc(dropX[d], dropY[d], DROP_RADIUS, 0, Math.PI * 2);
      }
      ctx.fillStyle = surfaceTone;
      ctx.fill();
    }
    ctx.restore();
    if (BORDER_STROKE <= 0) return;
    const half = BORDER_STROKE / 2;
    roundRectPath(ctx, half, half, W - BORDER_STROKE, H - BORDER_STROKE, rounded - half);
    ctx.lineWidth = BORDER_STROKE;
    ctx.strokeStyle = borderBase;
    ctx.stroke();
    const rim = ctx.createLinearGradient(W, H, 0, 0);
    rim.addColorStop(0, borderTone);
    rim.addColorStop(0.3, borderFade);
    rim.addColorStop(0.7, borderFade);
    rim.addColorStop(1, borderTone);
    ctx.strokeStyle = rim;
    ctx.stroke();
  }
  function loop(now) {
    const dt = last ? Math.min((now - last) / 1000, 1 / 30) : 1 / 60;
    last = now;
    pointer.vx *= 0.8;
    pointer.vy *= 0.8;
    if (!asleep) {
      const worst = step(dt);
      draw();
      if (!hovering && flying === 0 && worst < STILL) quiet++;
      else quiet = 0;
      if (quiet > SLEEP_FRAMES) {
        freeze();
        draw();
      }
    }
    requestAnimationFrame(loop);
  }
  const wake = () => {
    asleep = false;
    quiet = 0;
  };
  const toLocal = (e) => {
    const rect = root.getBoundingClientRect();
    const sx = rect.width > 0 ? W / rect.width : 1;
    const sy = rect.height > 0 ? H / rect.height : 1;
    return { x: (e.clientX - rect.left) * sx, y: (e.clientY - rect.top) * sy };
  };
  root.addEventListener('mouseenter', (e) => {
    hovering = true;
    const p = toLocal(e);
    pointer.x = p.x;
    pointer.y = p.y;
    pointer.vx = 0;
    pointer.vy = 0;
    wake();
  });
  root.addEventListener('mousemove', (e) => {
    const p = toLocal(e);
    pointer.vx = p.x - pointer.x;
    pointer.vy = p.y - pointer.y;
    pointer.x = p.x;
    pointer.y = p.y;
    wake();
  });
  root.addEventListener('mouseleave', () => {
    hovering = false;
    pointer.x = -9999;
    pointer.y = -9999;
    pointer.vx = 0;
    pointer.vy = 0;
    wake();
  });
  root.addEventListener('pointerdown', (e) => {
    const p = toLocal(e);
    pointer.x = p.x;
    pointer.y = p.y;
    splash(p.x);
    wake();
  });
  const observer = new ResizeObserver(() => {
    build();
    draw();
  });
  observer.observe(root);
  setInterval(() => {
    if (Math.abs(pixelScale() - pixScale) < 0.02) return;
    raster();
    draw();
  }, 300);
  build();
  draw();
  requestAnimationFrame(loop);
}
document.addEventListener('DOMContentLoaded', () => {
  document.querySelectorAll('.water-button').forEach(mountWaterButton);
});

There is also the marquee tag as the og method, this a slightly more polished version.

HTML
<div class="marquee">
  <div class="marquee-track">
    <img class="marquee-item" src="button1.gif" width="88" height="31" alt="Friend 1" />
    <img class="marquee-item" src="button2.gif" width="88" height="31" alt="Friend 2" />
    <img class="marquee-item" src="button3.gif" width="88" height="31" alt="Friend 3" />

    <img class="marquee-item" src="button1.gif" width="88" height="31" alt="" aria-hidden="true" />
    <img class="marquee-item" src="button2.gif" width="88" height="31" alt="" aria-hidden="true" />
    <img class="marquee-item" src="button3.gif" width="88" height="31" alt="" aria-hidden="true" />
  </div>
</div>
CSS
.marquee {
  overflow: hidden;
}

.marquee-track {
  display: flex;
  width: max-content;
  gap: 8px;
  animation: marquee-scroll 24s linear infinite;
}

.marquee:hover .marquee-track {
  animation-play-state: paused;
}

@keyframes marquee-scroll {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-50%);
  }
}

.marquee-item {
  display: block;
  flex-shrink: 0;
}

Visit w3schools glassmorphism generator!

WHUAU! I'm frosted!

HTML
<div class="glass-panel">
  <p>WHUAU! I'm frosted!</p>
</div>
CSS
.glass-panel {
  position: relative;
  border-radius: 0;

  padding: 20px;
  background: rgba(255, 255, 255, 0.48);
  border: 1px solid rgba(255, 255, 255, 0.30);
  backdrop-filter: blur(13px) saturate(208%);
  -webkit-backdrop-filter: blur(13px) saturate(208%);
}

For headings you want filled with a color gradient.

Gradient Text oooOOoo

HTML
<h1 class="gradient-text">Gradient Text oooOOoo</h1>
CSS
.gradient-text {
  font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
  font-weight: 700;
  font-size: 2.8rem;
  margin: 0;
  line-height: 1.25;
  background: linear-gradient(180deg, #ffb3d1 0%, #ff6fa5 45%, #e14f86 100%);
  -webkit-background-clip: text;
  background-clip: text;
  color: transparent;
}

Remembers what you picked (localStorage) and falls back to your OS setting if you haven't picked anything yet.

This card has its own light/dark state, click me!

HTML
<button class="theme-toggle" id="theme-toggle" type="button" aria-label="Toggle dark mode">
  <span class="theme-icon sun-icon" aria-hidden="true">☀️</span>
  <span class="theme-icon moon-icon" aria-hidden="true">🌙</span>
</button>
CSS
:root {
  --bg: #fdf6f0;
  --fg: #1a3f7a;
}
:root[data-theme="dark"] {
  --bg: #0a1522;
  --fg: #e9f1fb;
}

body {
  background: var(--bg);
  color: var(--fg);
  transition: background 0.3s ease, color 0.3s ease;
}

.theme-toggle {
  position: relative;
  width: 34px;
  height: 34px;
  border-radius: 50%;
  border: 1px solid rgba(128, 128, 128, 0.35);
  background: rgba(255, 255, 255, 0.6);
  cursor: pointer;
}
:root[data-theme="dark"] .theme-toggle {
  background: rgba(255, 255, 255, 0.1);
}

.theme-icon {
  position: absolute;
  inset: 0;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1rem;
  transition: opacity 0.4s ease, transform 0.4s ease;
}
:root[data-theme="light"] .sun-icon {
  opacity: 1;
  transform: rotate(0deg) scale(1);
}
:root[data-theme="light"] .moon-icon {
  opacity: 0;
  transform: rotate(-90deg) scale(0.6);
}
:root[data-theme="dark"] .sun-icon {
  opacity: 0;
  transform: rotate(90deg) scale(0.6);
}
:root[data-theme="dark"] .moon-icon {
  opacity: 1;
  transform: rotate(0deg) scale(1);
}
JavaScript
// Run this part as early as possible, ideally inline in <head>, before any
// CSS paints, so the page never flashes the wrong theme on first load.
(function () {
  var stored = localStorage.getItem('theme');
  var theme = stored || (window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light');
  document.documentElement.setAttribute('data-theme', theme);
})();

// This part can run anywhere after the <button id="theme-toggle"> exists in your code.
document.addEventListener('DOMContentLoaded', () => {
  const themeToggle = document.getElementById('theme-toggle');
  if (!themeToggle) return;
  themeToggle.addEventListener('click', () => {
    const current = document.documentElement.getAttribute('data-theme');
    const next = current === 'dark' ? 'light' : 'dark';
    document.documentElement.setAttribute('data-theme', next);
    localStorage.setItem('theme', next);
  });
});

My deviders for organisation.

HTML
<!-- normal -->
<div class="bubble-divider"></div>

<!-- dashed -->
<div class="bubble-divider bubble-divider-dashed"></div>
CSS
.bubble-divider {
  width: 100%;
  height: 6px;
  margin: 26px 0;
  border-radius: 999px;
  background: linear-gradient(90deg, #9fe0ea 0%, #3f7fc9 55%, #1a3f66 100%);
}

/* -------------------------------- */
/* remove this if you dont wanna use dark mode */
:root[data-theme="dark"] .bubble-divider {
  background: linear-gradient(90deg, #e4c770 0%, #e69c2c 55%, #a86539 100%);
}
/* -------------------------------- */

.bubble-divider-dashed {
  height: 0;
  border-radius: 0;
  background: none;
  box-shadow: none;
  border-top: 2px dashed var(--card-border-dashed, rgba(26, 63, 102, 0.4));
}

/* -------------------------------- */
/* remove this if you dont wanna use dark mode */
:root[data-theme="dark"] .bubble-divider-dashed {
  border-top-color: rgba(204, 154, 82, 0.4);
}
/* -------------------------------- */
topics.exe