Docs

Water Drop Grid

A water drop grid is a visual effect where grid elements ripple or distort like water droplets when interacted with, creating a fluid and organic animation.

Installation

Install dependencies

npm install framer-motion lucide-react

Run the following command

It will create a new file water-drop-grid.tsx inside the components/mage-ui/background directory.

mkdir -p components/mage-ui/background && touch components/mage-ui/background/water-drop-grid.tsx

Paste the code

Open the newly created file and paste the following code:

"use client";
 
import anime from "animejs";
import React from "react";
 
const WaterDropGrid: React.FC = () => {
  return (
    <div className="relative grid place-content-center bg-slate-900 px-8 py-12">
      <DotGrid />
    </div>
  );
};
 
const GRID_WIDTH = 25;
const GRID_HEIGHT = 20;
 
const DotGrid: React.FC = () => {
  const handleDotClick = (e: React.MouseEvent<HTMLDivElement>) => {
    const target = e.target as HTMLElement;
 
    // Safely access dataset.index with fallback
    const index = parseInt(target.dataset?.index || "0");
 
    anime({
      targets: ".dot-point",
      scale: [
        { value: 1.35, easing: "easeOutSine", duration: 250 },
        { value: 1, easing: "easeInOutQuad", duration: 500 },
      ],
      translateY: [
        { value: -15, easing: "easeOutSine", duration: 250 },
        { value: 0, easing: "easeInOutQuad", duration: 500 },
      ],
      opacity: [
        { value: 1, easing: "easeOutSine", duration: 250 },
        { value: 0.5, easing: "easeInOutQuad", duration: 500 },
      ],
      delay: anime.stagger(100, {
        grid: [GRID_WIDTH, GRID_HEIGHT],
        from: index,
      }),
    });
  };
 
  const dots: JSX.Element[] = [];
  let index = 0;
 
  for (let i = 0; i < GRID_WIDTH; i++) {
    for (let j = 0; j < GRID_HEIGHT; j++) {
      dots.push(
        <div
          className="group cursor-crosshair rounded-full p-2 transition-colors hover:bg-slate-600"
          data-index={index}
          key={`${i}-${j}`}
        >
          <div
            className="dot-point h-2 w-2 rounded-full bg-gradient-to-b from-slate-700 to-slate-400 opacity-50 group-hover:from-indigo-600 group-hover:to-white"
            data-index={index}
          />
        </div>
      );
      index++;
    }
  }
 
  return (
    <div
      onClick={handleDotClick}
      style={{ gridTemplateColumns: `repeat(${GRID_WIDTH}, 1fr)` }}
      className="grid w-fit"
    >
      {dots}
    </div>
  );
};
 
export default WaterDropGrid;