npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

modgrad

v0.1.4

Published

Beautiful, optionally animated mesh / blurry / grainy gradient backgrounds for React.

Downloads

861

Readme

modgrad

Beautiful, optionally animated mesh / blurry / grainy gradient backgrounds for React. One component, zero runtime dependencies, SSR-safe, no canvas or WebGL.

Reproduce the soft Arc-card look, build flowing animated hero backgrounds, or wash a translucent gradient over a photo — all from a single <Gradient />.

→ Live demo

bun add modgrad   # or npm / pnpm / yarn

Quick start

The easiest way — wrap your content and it sits on top automatically (no position or z-index wiring needed):

import { Gradient } from "modgrad";

function Card() {
  return (
    <Gradient preset="arc" grain style={{ borderRadius: 24, padding: 32 }}>
      <h1>Your content</h1>
    </Gradient>
  );
}

When you pass children, <Gradient> renders a self-contained box: the gradient fills it and the children sit above (their flex/grid layout is preserved, and they stay interactive).

As a background layer (no children)

With no children it's a bare fill layer — drop it into your own position: relative container. Because it's absolutely positioned, sibling content must be elevated (give it position: relative / a z-index), or it will be painted under the gradient:

<div style={{ position: "relative" }}>
  <Gradient preset="arc" grain />
  <div style={{ position: "relative", zIndex: 1 }}>Your content</div>
</div>

(Prefer the wrapper form above — it avoids this entirely.) The layer is pointer-events: none and aria-hidden, so it never blocks clicks.

Recipes

// The Arc card gradient
<Gradient preset="arc" grain={0.16} />

// Custom mesh of your brand colors
<Gradient colors={["#e8385e", "#b13ad8", "#4920d0", "#f6d8ec"]} grain blur={30} />

// Living, animated hero background that reacts to the cursor
<Gradient preset="sunset" animate interactive grain />

// Liquid: organic swirls & waves instead of plain circles (pure CSS/SVG)
<Gradient colors={["#e8385e", "#b13ad8", "#4920d0", "#ff7eb3"]} variant="liquid" animate />

// ...or warp any mesh / aurora and tune it
<Gradient preset="ocean" warp={{ scale: 2, intensity: 110 }} animate />

// Translucent overlay on top of a photo / video
<div style={{ position: "relative" }}>
  <img src="/photo.jpg" />
  <Gradient
    colors={["#ff5e62", "#7b2ff7", "#1fa2ff"]}
    opacity={0.7}
    blendMode="overlay"
  />
</div>

// Theme-aware: follows the OS, or force light/dark
<Gradient preset="arc" theme="system" />
<Gradient
  theme="dark"
  background={{ light: "#f4ecff", dark: "#160a2e" }}
  colors={{
    light: ["#f4768f", "#c98bff", "#7c6cff"],
    dark: ["#e8385e", "#b13ad8", "#4920d0"],
  }}
/>

// Full-viewport app background
<Gradient preset="ocean" fixed animate />

// Precise control: place each color blob yourself (x/y are 0–100)
<Gradient
  colors={[
    { color: "#e8385e", x: 20, y: 18, size: 70 },
    { color: "#4920d0", x: 75, y: 90, size: 80 },
  ]}
/>

Props

| Prop | Type | Default | Description | | ------------- | ------------------------------------------------------- | ----------- | --------------------------------------------------------------------- | | colors | Colors \| { light; dark } | — | The colors. A Blob is { color, x?, y?, size?, falloff?, opacity? }. Can differ per theme. | | preset | PresetName | — | A curated palette + layout (see below). colors overrides it. | | theme | "system" \| "light" \| "dark" | "system" | system follows the OS and updates live. Picks { light, dark } values. | | variant | "mesh" \| "aurora" \| "liquid" \| "linear" \| "radial" \| "conic" | "mesh" | How the colors are arranged. liquid = mesh with warp on. | | angle | number | 135 | Angle for linear / conic. | | background | string \| { light; dark } | preset/theme| Solid color painted behind every layer. Can differ per theme. | | grain | boolean \| number | false | SVG film grain. true = 0.15, or pass 01. | | grainScale | number | 180 | Grain fineness (smaller = finer/denser). | | grainFrequency | number | — | Set the noise baseFrequency directly (overrides grainScale). | | grainOctaves | number | 2 | Noise octaves — more = softer/cloudier, fewer = tighter. | | dither | boolean \| number | true | Fine anti-banding dither that hides 8-bit contour rings on smooth/dark gradients. false / 0 = none, or 01 to tune. Separate from grain. | | blur | number | 0 | Softness. Baked into the blobs for mesh/aurora (filter-free, no flicker); a CSS blur in px for linear/radial/conic. | | warp | boolean \| { scale?; intensity?; detail? } | false | Warp the color layers into organic swirls & waves via an SVG noise filter (mesh / aurora / liquid). scale = swirl size, intensity = px pushed, detail = noise octaves (1–4). On by default for variant="liquid". | | animate | boolean \| { speed?: number } | false | Slow organic drift. Honors prefers-reduced-motion. | | interactive | boolean | false | Layers drift toward the pointer. | | opacity | number | 1 | Overall opacity (for overlays). | | blendMode | CSS mix-blend-mode | — | Blend against what's behind it (for overlays). | | fixed | boolean | false | Render as a fixed full-viewport layer. | | zIndex | number | — | Stacking order. | | seed | number | 1 | Deterministic auto-layout & animation seed. | | className / style / children | — | — | Forwarded to the root element. |

Variants

  • mesh — layered radial "blobs", one per color. The smooth Arc/Stripe look. Default.
  • aurora — same blobs blended with screen for glowing, neon overlaps. Wants a dark background (the screen blend washes out on light ones).
  • liquidmesh with the warp filter on: the blobs melt into organic swirls and waves, the shader-gradient look without WebGL. Equivalent to <Gradient variant="mesh" warp />; add animate and the colors flow through the warp. Tune via the warp object.
  • linear / radial / conic — classic CSS gradients across your colors.

<Noise /> — texture without the gradient

Just the grain. Add a blur to frost what's behind it (a textured backdrop-blur) and a tint for paper-like tones. Overlays anything, or wraps content like <Gradient>.

import { Noise } from "modgrad";

// paper-textured, tinted panel wrapping content
<Noise intensity={0.5} tint="#b8a575" tintAmount={0.25} style={{ padding: 24 }}>
  <p>Looks like paper.</p>
</Noise>

// frosted, textured glass over whatever's behind it
<Noise blur={10} intensity={0.35} tint="#fff" tintAmount={0.08} />

| Prop | Type | Default | Description | | --- | --- | --- | --- | | intensity | boolean \| number | 0.15 | Grain strength (true = 0.15). | | scale / frequency / octaves | number | 180 / — / 2 | Grain texture controls (same as grain* on Gradient). | | blur | number | 0 | Backdrop blur in px — frosts the content behind. | | tint | string | — | Wash color painted over the backdrop. | | tintAmount | number | 0.12 | Tint opacity. | | opacity / blendMode / fixed / zIndex / className / style / children | — | — | Same as Gradient. |

Presets

arc · sunset · ocean · aurora · peach · mint · dusk · candy · mono · ember

import { presets } from "modgrad";
Object.keys(presets); // inspect or remix any palette

How it works

  • Mesh = stacked radial-gradient layers over a base color, auto-placed toward the corners/edges (override with explicit x/y).
  • Grain = an inline feTurbulence SVG noise tile (opaque, mid-gray-centered) blended with overlay — crisp at any DPI, weighs nothing, no image assets.
  • Dither = the same noise, but finer, single-octave and near-invisible, on by default. Because it's symmetric (lightens and darkens), it scatters the 8-bit band edges that make smooth/dark gradients show contour rings. Tune with dither (01), or dither={false} for a pixel-clean gradient.
  • Blur is applied only to the color layers, so grain stays sharp on top.
  • Warp / liquid feeds the blobs through a static feTurbulence + feDisplacementMap filter — a fixed "lens" that bends circles into swirls and waves. The filter is never animated (that boils/jitters); instead the rAF drift slides the colors through it, so motion stays buttery-smooth.
  • Animate / interactive drive per-layer translate3d from a single requestAnimationFrame loop (GPU-friendly, parks itself when idle).

No canvas, no WebGL, no dependencies — just DOM and CSS, so it renders on the server and streams fine.

Development

bun install
bun run dev    # live demo gallery at http://localhost:3000
bun run build  # emits dist/ (ESM + .d.ts)

License

MIT