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

easy-mesh-gradient

v0.2.1

Published

Generate beautiful CSS mesh gradients with easing. Zero dependencies, full TypeScript support.

Readme

Easy Mesh Gradient

Frame 2 (2)

A lightweight, zero-dependency library for generating beautiful CSS mesh gradients with TypeScript support.

Try it visually in the live editor.

Installation

npm install easy-mesh-gradient

Quick Start

import easyMeshGradient from "easy-mesh-gradient";

// Simple usage with defaults
const gradient = easyMeshGradient();
document.body.style.backgroundImage = gradient;

With React

The library is framework-independent — it just returns a CSS string — so in React it's one line of style:

import { useMemo } from "react";
import easyMeshGradient from "easy-mesh-gradient";

function Hero({ seed }: { seed: string }) {
  const backgroundImage = useMemo(() => easyMeshGradient({ seed }), [seed]);
  return <div style={{ backgroundImage }}>…</div>;
}

Memoize (or generate outside the component) so the gradient isn't rebuilt on every render.

Usage

With Generation Options

import easyMeshGradient from "easy-mesh-gradient";

const gradient = easyMeshGradient({
  seed: "my-gradient", // reproducible output
  pointCount: 8,
  hueRange: [180, 240], // blues only
  saturationRange: [0.6, 1],
  lightnessRange: [0.4, 0.7],
  scaleRange: [0.5, 1.5],
});

With Custom Points

import easyMeshGradient from "easy-mesh-gradient";

const gradient = easyMeshGradient({
  points: [
    { x: 0.1, y: 0.1, h: 120, s: 0.8, l: 0.6, scale: 1 },
    { x: 0.9, y: 0.9, h: 300, s: 0.6, l: 0.4, scale: 1.5 },
  ],
  easingStops: 20,
});

With a Custom Easing

import easyMeshGradient, { easeInOutExpo } from "easy-mesh-gradient";

const gradient = easyMeshGradient({
  easing: easeInOutExpo,
  easingStops: 15,
});

// Or any (x: number) => number mapping [0, 1] to [0, 1]
const custom = easyMeshGradient({ easing: (x) => x * x });

API Reference

easyMeshGradient(options?)

Returns a CSS gradient string (stacked radial-gradients over an opaque base layer) for use as a background-image. The first point paints on top and sets the base color.

Blobs are circles by default, so the gradient looks right on any element — wide banners included. Pass shape: "ellipse" if you want the blobs to stretch with the element's proportions instead.

Options

All options are optional.

| Option | Type | Default | Description | | ----------------- | ----------------------- | ---------------- | --------------------------------------------------------------------------- | | points | Point[] | generated | Explicit points. When provided, generation options are ignored. | | shape | "circle" \| "ellipse" | "circle" | Blob shape. Circles stay round on any element; ellipses stretch with it. | | easing | (x: number) => number | easeInOutCubic | Controls the alpha falloff curve of each point. | | easingStops | number | 10 | Number of color stops per point (min 2). More stops = smoother, longer CSS. | | seed | string | random | Seed for reproducible generation. Same seed, same gradient. | | pointCount | number | 5 | Number of points to generate (min 1). | | hueRange | [number, number] | [0, 360] | Hue range. min > max wraps around the color wheel (e.g. [300, 60]). | | saturationRange | [number, number] | [0.5, 1] | Saturation range (0–1). | | lightnessRange | [number, number] | [0.5, 1] | Lightness range (0–1). | | scaleRange | [number, number] | [0.5, 2] | Range for each point's fade size. | | pointsGenerator | (options?) => Point[] | scatter | Custom point generation function. |

Point

type Point = {
  x: number; // 0-1, left to right
  y: number; // 0-1, top to bottom
  h: number; // hue, 0-360
  s: number; // saturation, 0-1
  l: number; // lightness, 0-1
  scale: number; // fade size multiplier
};

Exports

Everything is exported from the package root:

import easyMeshGradient, {
  // Generators
  defaultPointsGenerator,
  gridPointsGenerator,

  // Easings
  easings, // Record<EasingName, EasingFunction>
  linear,
  easeInQuad,
  easeOutQuad,
  easeInOutQuad,
  easeInCubic,
  easeOutCubic,
  easeInOutCubic,
  easeInOutSine,
  easeInOutExpo,

  // Validation
  validatePoint,
  validatePoints,

  // Color utilities
  hslToRgb,
  hslToHex,
  hexToHsl,
  hslToOklch,
  pointToHsla,
  pointToHsl,
  pointToHex,
  pointToRgb,
  pointToOklch,

  // Canvas rendering
  renderMeshGradient,
} from "easy-mesh-gradient";

import type {
  Point,
  GradientOptions,
  EasingOptions,
  ShapeOptions,
  GradientShape,
  PointGenerationOptions,
  EasingFunction,
  EasingName,
  CanvasRenderOptions,
  GrainOptions,
} from "easy-mesh-gradient";

Advanced Usage

Grid Pattern Generator

import easyMeshGradient, { gridPointsGenerator } from "easy-mesh-gradient";

// 3x3 grid of points with randomized colors
const gradient = easyMeshGradient({
  pointsGenerator: (options) => gridPointsGenerator(options, 3, 3),
  seed: "structured",
});

Rendering to Canvas (image export)

renderMeshGradient draws the exact same gradient onto a 2D canvas context, which makes PNG/JPEG export easy:

import { renderMeshGradient } from "easy-mesh-gradient";

const canvas = document.createElement("canvas");
canvas.width = 1920;
canvas.height = 1080;

renderMeshGradient(canvas.getContext("2d")!, { seed: "wallpaper" });

canvas.toBlob((blob) => {
  // download or upload the image
}, "image/png");

It also supports an optional monochrome film-grain overlay:

renderMeshGradient(ctx, {
  seed: "wallpaper",
  grain: {
    density: 0.5, // fraction of pixels affected (0-1)
    intensity: 0.15, // maximum luminance shift (0-1)
  },
});

Extracting a Color Palette

import {
  defaultPointsGenerator,
  pointToHex,
  pointToOklch,
} from "easy-mesh-gradient";

const points = defaultPointsGenerator({ seed: "brand", pointCount: 5 });
const hexPalette = points.map(pointToHex);
const oklchPalette = points.map(pointToOklch);

Building an Easing Picker

import { easings, type EasingName } from "easy-mesh-gradient";

for (const [name, fn] of Object.entries(easings)) {
  console.log(name, fn(0.5));
}

Input Validation

All inputs are validated and normalized automatically — values are clamped to valid ranges and missing properties get sensible defaults. validatePoint / validatePoints are exported if you want the same normalization for your own data.

Examples

Reproducible Gradients

// These are always identical
const a = easyMeshGradient({ seed: "hello" });
const b = easyMeshGradient({ seed: "hello" });

Performance Tips

  • Generate gradients once and reuse the string; regenerating on every render is wasted work.
  • Lower easingStops for shorter CSS output; raise it if you see banding.
  • Fewer points means fewer stacked radial-gradient layers for the browser to composite.

Migrating from 0.1.x

  • Single entry point — subpath imports (easy-mesh-gradient/easings, /types, /generators, /validation) were removed. Import everything from "easy-mesh-gradient".
  • Seeded output changed — the internal PRNG was upgraded (better distribution). The same seed produces a different (nicer) gradient than 0.1.x.
  • Blobs are circles now — 0.1.x used the CSS default ellipse, which stretches on oblong elements. Pass shape: "ellipse" for the old behavior.
  • New in 0.2easings map, EasingName type, color utilities (pointToHex, hslToOklch, …), and renderMeshGradient for canvas/image export.

License

MIT — created by Steven Frady