Studio KitAnimated Backgrounds and Visual Effectsno dependencies

GridPulse

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 props
12
6
3

Installation

Copies the component source and its CSS Module into your project.

npx motionfoundry add grid-pulse

Writes 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.

example.tsx
1import { GridPulse } from "@motionfoundry/ui";2 3export function Example() {4  return (5    <GridPulse />6  );7}

Props

PropTypeDefault
cols

Number of grid columns.

number12
rows

Number of grid rows.

number6
pulseColor

Fill color of a pulsing cell.

string'#38bdf8'
duration

Pulse cycle length in seconds.

number3
children

Foreground content centered above the grid.

React.ReactNode'Grid Pulse' heading
className

Additional class merged onto the root element.

string''

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

components/ui/grid-pulse.tsx
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}