# Hazeglow > Soft, grainy, animated gradient backgrounds and mesh gradients for React, drawn on the GPU with WebGL2. Zero dependencies, about 13 kB gzipped. Free and MIT licensed. Design a gradient visually at https://hazeglow.dev/generator and copy its config. Formerly published as `@scoobynko/afterglow` with the component `Afterglow`; configs are unchanged. ## Install npm i hazeglow ## React ```tsx import { Hazeglow, parseConfig, presets } from "hazeglow"; export function Hero() { return (

Your headline

); } ``` - Props: `config` (required), `className`, `style`, `onUnsupported()` (called when WebGL2 is missing; keep a CSS background behind the canvas as a fallback). - The canvas fills its parent. It pauses when off screen and draws a single still frame when `prefers-reduced-motion` is set. - Browsers allow about 16 WebGL canvases per page. Keep live gradients few; use images of a frame elsewhere. ## Without React ```ts import { createRenderer, parseConfig } from "hazeglow/core"; const renderer = createRenderer(canvas); if (renderer) { const config = parseConfig(input); let time = 0; let last = performance.now(); const tick = (now: number) => { time += Math.min((now - last) / 1000, 0.1) * config.speed; last = now; renderer.render(config, time); requestAnimationFrame(tick); }; requestAnimationFrame(tick); } ``` `createRenderer` returns `{ render(config, time, pointer?), resize(width, height), dispose(), maxSize }`, or `null` without WebGL2. Resize in device pixels and render right after resizing. ## Config (version 1) Always pass a config through `parseConfig(input)`. It never throws, clamps numbers to their ranges and fills anything missing with defaults. - `shape`: "pill" | "band" | "blob" | "ring" | "mesh" - `center` [x, y] 0 to 1, `size` [w, h] 0 to 1.5, `roundness` 0 to 1, `softness` 0 to 1, `rotation` 0 to 360, `rampDirection` 0 to 1, `angle` 0 to 360, `warp` 0 to 1, `warpScale` 0.5 to 4 - `palette`: 2 to 10 colors, `background`: one color. A color is hex ("#rgb" or "#rrggbb"), `oklch(L C H)` or `var(--token)` (see Colors) - `mesh`: up to 16 points `[x, y, color]`, used when `shape` is "mesh" - `grain` 0 to 1, `motion` "none" | "drift" | "breathe" | "flow", `speed` 0 to 2, `loop` 0 to 30 seconds (0 never repeats) - `hover` 0 to 1 (0 is off), `hoverMode` "pull" | "push" - `effect` "none" | "dither" | "ascii" | "halftone" | "pixelate" | "glass", `effectSize` 2 to 64, `effectAmount` 0 to 1 Presets: `dusk`, `pearl`, `ember`, `horizon`, `ultraviolet`, `candy` via `import { presets }`. `randomConfig(seed)` makes a random config. `encodeConfig` and `decodeConfig` turn a config into a URL-safe string and back. ## Colors From 0.3.0, `palette`, `background` and mesh point colors can be hex, `oklch(L C H)` or a CSS variable such as `var(--brand)` or `var(--accent, #f59a22)`. The engine reads variables from the canvas's computed style, so a theme set on any ancestor works, and it redraws by itself when the `class`, `style` or `data-theme` attribute on `` or `prefers-color-scheme` changes. Always give a fallback in `var()`, because a missing variable draws black. `resolveConfig(config, element)` returns a copy with every `var()` replaced by the color it holds. Use it before `encodeConfig` (so a share link carries colors, not variable names) and anywhere there is no DOM, like a worker. `isColor(value)` checks the syntax and `colorToOklab(color, element?)` returns Oklab `[L, a, b]` or `null`. ## Share links https://hazeglow.dev/generator#c=&w=&h= ## Notes for coding agents - Prefer a config designed in the generator over inventing colors. - Hex works everywhere. Use `oklch()` or `var(--token)` when the gradient should follow the site's theme (needs hazeglow 0.3.0 or newer). - Do not stack CSS gradients on top of the canvas; put content above it instead.