Dot Grid
moco/dotgridFreeComponent
Full-viewport canvas dot grid that drifts toward the cursor; pauses when the tab is hidden, off under reduced motion.
Live preview
live · rendered by the registry
Rendered by moco on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://mocoui.site/r/dotgrid.jsonSource
1"use client";23import * as React from "react";4import { useReducedMotion } from "@/components/moco/hooks";5import "./dotgrid.css";67export interface DotGridProps {8 /** Grid pitch in px. */9 spacing?: number;10 /** Cursor influence radius in px. */11 radius?: number;12}1314/**15 * Sparse dot grid that reacts to the cursor. Pauses when the tab is hidden and16 * does not run at all under prefers-reduced-motion. Dot color is resolved from17 * the canvas's computed `color` (set to var(--moco-ink) in dotgrid.css), so it18 * stays visible in dark mode; only the alpha ramp is applied on top.19 */20export function DotGrid({ spacing = 34, radius = 130 }: DotGridProps) {21 const ref = React.useRef<HTMLCanvasElement>(null);22 const reduced = useReducedMotion();2324 React.useEffect(() => {25 if (reduced) return;26 const canvas = ref.current;27 const ctx = canvas?.getContext("2d");28 if (!canvas || !ctx) return;2930 let w = 0;31 let h = 0;32 let dpr = 1;33 const pointer = { x: -9999, y: -9999 };34 let raf = 0;35 let running = true;3637 // Base dot color, re-resolved on color-scheme change and resize.38 let rgb = "0,0,0";39 const resolveColor = () => {40 const m = getComputedStyle(canvas).color.match(/[\d.]+/g);41 if (m && m.length >= 3) rgb = `${m[0]},${m[1]},${m[2]}`;42 };4344 const resize = () => {45 dpr = Math.min(2, window.devicePixelRatio || 1);46 w = canvas.clientWidth;47 h = canvas.clientHeight;48 canvas.width = Math.floor(w * dpr);49 canvas.height = Math.floor(h * dpr);50 ctx.setTransform(dpr, 0, 0, dpr, 0, 0);51 resolveColor();52 };5354 const draw = () => {55 ctx.clearRect(0, 0, w, h);56 for (let x = spacing / 2; x < w; x += spacing) {57 for (let y = spacing / 2; y < h; y += spacing) {58 const dx = x - pointer.x;59 const dy = y - pointer.y;60 const d = Math.hypot(dx, dy);61 const k = d < radius ? 1 - d / radius : 0;62 const alpha = 0.07 + k * 0.26;63 const push = k * 4;64 const px = x + (d ? (dx / d) * push : 0);65 const py = y + (d ? (dy / d) * push : 0);66 ctx.fillStyle = `rgba(${rgb},${alpha.toFixed(3)})`;67 ctx.fillRect(px, py, 1, 1);68 }69 }70 if (running) raf = requestAnimationFrame(draw);71 };7273 const onMove = (e: PointerEvent) => {74 pointer.x = e.clientX;75 pointer.y = e.clientY;76 };77 const onLeave = () => {78 pointer.x = -9999;79 pointer.y = -9999;80 };81// … truncated
What it pulls in
Other registry items
Files it writes
More from moco
All 20 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Codecode | moco | Components | Free | 1 dep · 3 files | |
| Comparecompare | moco | Components | Free | no deps · 2 files | |
| Count Upcountup | moco | Components | Free | no deps · 2 files | |
| Covercover | moco | Components | Free | no deps · 2 files | |
| Diagram Kitdiagram | moco | Components | Free | no deps · 2 files | |
| Figurefigure | moco | Components | Free | no deps · 2 files | |
| Hookshooks | moco | Components | Free | no deps | |
| Islandisland | moco | Components | Free | no deps · 2 files |
