A bordered cell grid where individual cells softly flash with an accent color on deterministic, per-cell offsets set through CSS custom properties, under a radial vignette.
Preview
Grid Pulse
12 × 6 cells, CSS-only
Customize
4 propsInstallation
Copies the component source and its CSS Module into your project.
npx motionfoundry add grid-pulseWrites components/ui/grid-pulse.tsx and components/styles/grid-pulse.module.css.
Usage
Updates live as you change the controls — only props that differ from the defaults are included.
1import { GridPulse } from "@motionfoundry/ui";2 3export function Example() {4 return (5 <GridPulse />6 );7}Props
Accessibility
The grid layer is aria-hidden and pointer-events: none; children keep their semantics. Per-cell delays come from a seeded rand(n) via --mf-gp-delay, so SSR output is stable. Under prefers-reduced-motion the pulses are disabled and only the static grid lines remain.
Toggle prefers-reduced-motion in your OS or browser devtools (Rendering → Emulate CSS media feature) to verify the reduced-motion state.
Source
1"use client";2 3import * as React from "react";4import styles from "../styles/grid-pulse.module.css";5 6export interface GridPulseProps {7 /** Number of grid columns */8 cols?: number;9 /** Number of grid rows */10 rows?: number;11 /** Cell pulse color */12 pulseColor?: string;13 /** Pulse cycle duration in seconds */14 duration?: number;15 /** Foreground content rendered above the grid */16 children?: React.ReactNode;17 /** Optional className merged onto the root */18 className?: string;19}20 21const rand = (n: number) => {22 const x = Math.sin(n * 9301 + 49297) * 233280;23 return x - Math.floor(x);24};25 26export function GridPulse({27 cols = 12,28 rows = 6,29 pulseColor = "#38bdf8",30 duration = 3,31 children,32 className = "",33}: GridPulseProps) {34 const c = Math.max(1, Math.round(cols));35 const r = Math.max(1, Math.round(rows));36 const styleVars = {37 "--mf-gp-color": pulseColor,38 "--mf-gp-duration": `${duration > 0 ? duration : 3}s`,39 "--mf-gp-cols": c,40 "--mf-gp-rows": r,41 } as React.CSSProperties;42 43 return (44 <div style={styleVars} className={`${styles.root} ${className}`.trim()}>45 <div aria-hidden="true" className={styles.grid}>46 {Array.from({ length: c * r }, (_, i) => (47 <span48 key={i}49 className={styles.cell}50 style={{ "--mf-gp-delay": `-${(rand(i) * 6).toFixed(2)}s` } as React.CSSProperties}51 />52 ))}53 </div>54 <div className={styles.content}>55 {children ?? (56 <div className={styles.copy}>57 <h3 className={styles.title}>Grid Pulse</h3>58 <p className={styles.subtitle}>59 {c} × {r} cells, CSS-only60 </p>61 </div>62 )}63 </div>64 </div>65 );66}