Package Exports
- grain-gradient
- grain-gradient/react
- grain-gradient/webgl
- grain-gradient/webgl/react
Readme
grain-gradient
Lightweight TypeScript helpers for WebGL shader mesh + grain gradients.
v2 is WebGL-only. The library now renders through a single WebGL fragment shader. CSS/SVG gradient generation APIs from v1 (
createGrainGradientCSS,createMeshGradient,createTurbulenceNoise,createAndroidCanvasFallbackStyle, and related Android/canvas fallback helpers) have been removed.

Installation
npm i grain-gradientWebGL shader renderer
grain-gradient renders both the mesh gradient and the grain texture in one WebGL fragment shader. The React component keeps only a minimal baseColor background behind the canvas, so SSR and unsupported WebGL environments do not render a blank transparent box.
import { GrainGradient, presets } from "grain-gradient/react";
export function Hero() {
return (
<GrainGradient
{...presets["Aurora Citrus"]}
motionPreset="drift"
motionSpeed={38}
motionIntensity={46}
swirl={30}
opacity={0.22}
style={{ minHeight: "100vh" }}
/>
);
}The component creates a <canvas> context on the client. If WebGL is unavailable or the WebGL context is lost, the component keeps only the baseColor background; it does not provide a CSS/SVG or 2D canvas fallback.
In SSR frameworks such as Next.js, render it from a client boundary ("use client") or with a dynamic import using ssr: false.
import dynamic from "next/dynamic";
const GrainGradient = dynamic(
() => import("grain-gradient/react").then((mod) => mod.GrainGradient),
{ ssr: false },
);Framework-agnostic renderer
import { createWebGLMeshRenderer } from "grain-gradient";
const canvas = document.querySelector("canvas")!;
const renderer = createWebGLMeshRenderer(canvas, {
colors: ["#c2e812", "#ff7f11", "#ee4266", "#2a1e5c"],
motionPreset: "drift",
motionSpeed: 38,
motionIntensity: 46,
opacity: 0.22,
});
renderer?.start();Call renderer.update(options) when controls change, renderer.resize() when the canvas layout changes, and renderer.destroy() during cleanup.
Performance defaults
Animated fullscreen rendering is tuned conservatively by default:
fps: 30maxPixelRatio: 1.25motionMaxPixelRatio: 0.75pauseWhenHidden: true
Raise these only when you need sharper or smoother animated rendering.
Development
npm run build: compile the TypeScript source todist/npm run build:playground: build the Vite React playground todist-playground/npm run test: run the Node test suite after buildingnpm run lint: check the codebase with oxlintnpm run format:check: verify formatting with oxfmtnpm run playground: open the Vite playground at/
Local playground
Run the Vite-powered playground with hot reload:
npm run devThen open http://localhost:5173/.