# Shaderz docs

> Free animated WebGL gradient backgrounds for any website. No account, no API key, no npm package, no build step. One script tag and one HTML attribute.

This page is written for both humans and coding agents (Claude Code, Cursor, Copilot, Windsurf, v0, Lovable, Bolt…). Share this URL with your agent and ask it to add the background.

- Markdown version: https://www.shaderz.fun/docs.md
- LLM index: https://www.shaderz.fun/llms.txt
- Runtime script: https://www.shaderz.fun/shaderz.js
- Visual editor: https://www.shaderz.fun/editor

Using Shaderz is free for personal and commercial projects. No attribution required.

## Quick start for coding agents

Follow these steps exactly.

1. Load the runtime once per page, ideally just before `</body>` or in `<head>` with `defer`:

~~~html
<script src="https://www.shaderz.fun/shaderz.js" defer></script>
~~~

2. Add a `data-shaderz` attribute to the element that should get the animated background. The element keeps its content. The script inserts a `<canvas>` behind the content of that element, sized to it.

~~~html
<section data-shaderz="s=aurora&c1=22c55e&c2=06b6d4&c3=a855f7&bg=020617" style="min-height: 80vh">
  <h1>Your headline</h1>
</section>
~~~

3. Pick the config. The value of `data-shaderz` is a query string of parameters (see the parameters table). If the user gave you a Shaderz link, take the config from it (see "From a Shaderz link"). If not, pick one of the ready-made configs below or compose one from the brand colors.

That is the whole integration. Do not install anything else.

### Rules for agents

- Do not copy shader code into the project. Use the script.
- Keep text readable: if text sits on top of the background, check contrast. Add an overlay such as `background: linear-gradient(rgba(0,0,0,.35), rgba(0,0,0,.35))` on a child element if needed.
- Use `data-shaderz` on a dedicated empty element when the framework re-renders the container's children (React, Vue, Svelte). See the framework sections.
- Colors: write them as `rrggbb` without `#` in the attribute (`c1=ff7a18`). `%23ff7a18` and `#ff7a18` also work.
- Only parameters that differ from the defaults need to be present.
- The script respects `prefers-reduced-motion`: it renders a still frame for those users. Keep that behavior unless the user explicitly asks otherwise.

## From a Shaderz link

Users usually design their background in the editor and send you a link.

- **Editor link** like `https://www.shaderz.fun/editor?s=mesh&c1=ff6ec7`: everything after `?` is the config. Use it as is: `data-shaderz="s=mesh&c1=ff6ec7"`.
- **Gallery link** like `https://www.shaderz.fun/p/abc123xy`: fetch `https://www.shaderz.fun/api/presets/abc123xy`. The JSON response has a `config` field (the query string) and a ready-to-paste `snippet`.
- **Embed link** like `https://www.shaderz.fun/embed?s=aurora`: same as the editor link, the query string is the config.

Example response of the preset API:

~~~json
{
  "slug": "abc123xy",
  "name": "Midnight aurora",
  "config": "s=aurora&c1=22c55e&c2=06b6d4&c3=a855f7&bg=020617",
  "params": { "shader": "aurora", "c1": "#22c55e", "…": "…" },
  "snippet": "<div data-shaderz=\"s=aurora&c1=22c55e&c2=06b6d4&c3=a855f7&bg=020617\"></div>\n<script src=\"https://www.shaderz.fun/shaderz.js\" defer></script>"
}
~~~

## Preset library

If the user describes a mood instead of giving a link ("calm ocean", "neon cyberpunk", "warm and cozy"), pick a preset from the library instead of inventing values:

- Fetch `https://www.shaderz.fun/presets.json`. It contains 1000 presets: `{ id, name, shader, tags, config }`.
- Choose the preset whose `name` and `tags` best match the request. Tags cover moods (calm, energetic, dark, light), themes (ocean, space, coffee, saas…), colors and shader families.
- Use its `config` as the value of `data-shaderz`. To use brand colors, replace `c1`, `c2`, `c3` (and `bg`) in the config with the brand hex values.

~~~json
{ "id": "northern-lights-aurora", "name": "Northern Lights Aurora", "shader": "aurora",
  "tags": ["aurora", "northern lights", "night", "green", "purple", "sky", "dark", "calm"],
  "config": "s=aurora&c1=22c55e&c2=06b6d4&c3=a855f7&bg=020617&…" }
~~~

## Framework recipes

### Plain HTML, WordPress, Webflow, Framer, Shopify

Paste the script in the site's custom code (footer or head) and add the attribute on the section. In page builders that cannot add attributes, use an HTML embed block with an absolutely positioned div:

~~~html
<div data-shaderz="s=aurora&c1=22c55e&c2=06b6d4&c3=a855f7&bg=020617" aria-hidden="true"
     style="position:absolute;inset:0;z-index:0"></div>
~~~

### Full-page background

~~~html
<div data-shaderz="s=aurora&c1=22c55e&c2=06b6d4&c3=a855f7&bg=020617" aria-hidden="true"
     style="position:fixed;inset:0;z-index:-1"></div>
<script src="https://www.shaderz.fun/shaderz.js" defer></script>
~~~

### Next.js (App Router)

Load the script once in the root layout with `next/script`, then use the attribute on an empty, absolutely positioned div inside a relative section. Works with client-side navigation: the script watches the DOM and mounts new elements automatically.

~~~tsx
// app/layout.tsx
import Script from "next/script";

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        {children}
        <Script src="https://www.shaderz.fun/shaderz.js" strategy="afterInteractive" />
      </body>
    </html>
  );
}
~~~

~~~tsx
// any server or client component
export function Hero() {
  return (
    <section className="relative isolate min-h-[80vh] overflow-hidden">
      <div
        data-shaderz="s=aurora&c1=22c55e&c2=06b6d4&c3=a855f7&bg=020617"
        aria-hidden
        className="absolute inset-0 -z-10"
      />
      <h1 className="relative">Your headline</h1>
    </section>
  );
}
~~~

Use `strategy="afterInteractive"` (not `beforeInteractive`) so the canvas is added after hydration.

### React (Vite, CRA, Remix)

Add `<script src="https://www.shaderz.fun/shaderz.js" defer></script>` to `index.html` (or the root document), then use the same empty div pattern as in Next.js. Changing the `data-shaderz` value from React updates the background live.

For programmatic control:

~~~tsx
import { useEffect, useRef } from "react";

declare global {
  interface Window {
    Shaderz?: {
      mount: (el: Element, config?: string | Record<string, unknown>, opts?: { motion?: "auto" | "always"; dpr?: number; paused?: boolean }) => {
        set: (patch: string | Record<string, unknown>) => void;
        replace: (config: string | Record<string, unknown>) => void;
        pause: () => void;
        play: () => void;
        destroy: () => void;
      };
    };
  }
}

export function ShaderzBackground({ config }: { config: string }) {
  const ref = useRef<HTMLDivElement>(null);
  useEffect(() => {
    if (!ref.current || !window.Shaderz) return;
    const inst = window.Shaderz.mount(ref.current, config);
    return () => inst.destroy();
  }, [config]);
  return <div ref={ref} aria-hidden style={{ position: "absolute", inset: 0, zIndex: -1 }} />;
}
~~~

### Vue, Nuxt, Svelte, SvelteKit, Astro, Angular

Load the script once in the app shell, then bind the attribute on an empty element:

~~~html
<!-- Vue -->
<div :data-shaderz="config" aria-hidden="true" class="absolute inset-0 -z-10"></div>

<!-- Svelte -->
<div data-shaderz={config} aria-hidden="true" class="absolute inset-0 -z-10"></div>

<!-- Astro -->
<div data-shaderz="s=aurora&c1=22c55e&c2=06b6d4&c3=a855f7&bg=020617" aria-hidden="true" class="absolute inset-0 -z-10"></div>
<script is:inline src="https://www.shaderz.fun/shaderz.js" defer></script>
~~~

### Self-hosting

The script has no dependencies and talks to no server after loading. To remove the dependency on www.shaderz.fun, download it into the project and serve it yourself:

~~~bash
curl -o public/shaderz.js https://www.shaderz.fun/shaderz.js
~~~

Then use `<script src="/shaderz.js" defer></script>`.

### iframe (no script)

If scripts are not allowed, embed the background as an iframe:

~~~html
<iframe src="https://www.shaderz.fun/embed?s=aurora&c1=22c55e&c2=06b6d4&c3=a855f7&bg=020617" title="" aria-hidden="true" tabindex="-1"
  style="position:absolute;inset:0;width:100%;height:100%;border:0;z-index:-1;pointer-events:none"></iframe>
~~~

## Parameters

All parameters are optional. Short keys and long names are both accepted.

| Key | Long name | Type | Default | Values | Description |
| --- | --- | --- | --- | --- | --- |
| `s` | `shader` | enum | `gradient` | `gradient`, `mesh`, `aurora`, `liquid`, `blobs` | Shader family. See the shader families section. |
| `sh` | `shape` | enum | `plane` | `plane`, `sphere`, `water` | Surface shape. Only used when shader is gradient. |
| `c1` | `c1` | hex color | `#ff7a18` | `#rrggbb` or `rrggbb` | First color. |
| `c2` | `c2` | hex color | `#af002d` | `#rrggbb` or `rrggbb` | Second color. |
| `c3` | `c3` | hex color | `#319197` | `#rrggbb` or `rrggbb` | Third color. |
| `bg` | `bg` | hex color | `#000000` | `#rrggbb` or `rrggbb` | Background color. Also the 4th color of mesh, the sky of aurora, the base of blobs and liquid. |
| `sp` | `speed` | number | `0.4` | 0 to 2 | Animation speed. 0 freezes the animation. |
| `st` | `strength` | number | `1.2` | 0 to 3 | Displacement or warp amount. |
| `dn` | `density` | number | `1.1` | 0.1 to 4 | Detail scale. Higher means smaller features. |
| `fq` | `frequency` | number | `5.5` | 0 to 10 | Secondary noise and motion frequency. |
| `gr` | `grain` | number | `0.15` | 0 to 1 | Film grain amount. |
| `br` | `brightness` | number | `1.1` | 0.2 to 2 | Overall brightness multiplier. |
| `lt` | `light` | enum | `3d` | `3d`, `flat` | Lighting model. Only used when shader is gradient. |
| `rf` | `reflection` | number | `0.1` | 0 to 1 | Highlights and fresnel glow. |
| `wf` | `wireframe` | boolean (`1` / `0`) | `false` |  | Editor-only preview flag. Ignored by the script. |
| `cd` | `cDist` | number | `7` | 1 to 20 | Camera distance. Only used when shader is gradient. |
| `cp` | `cPolar` | number | `60` | 0 to 89 | Camera angle from above, in degrees. Only used when shader is gradient. |
| `ca` | `cAzimuth` | number | `0` | -180 to 180 | Camera rotation around the vertical axis, in degrees. Only used when shader is gradient. |
| `cz` | `zoom` | number | `1` | 0.3 to 3 | Camera zoom. Only used when shader is gradient. |

## Shader families

- **gradient**: a 3D surface displaced by noise, lit and viewed by a camera. Shapes: `plane` (rolling hills seen at an angle), `sphere` (a morphing blob), `water` (waves). Uses the camera parameters.
- **mesh**: flat mesh gradient with four soft color points (c1, c2, c3, bg) drifting around. Clean SaaS look.
- **aurora**: glowing horizontal ribbons over a dark sky. Use a dark `bg`.
- **liquid**: domain-warped fluid with metallic highlights. Good for chrome, marble, lava.
- **blobs**: soft metaballs floating on the background. Playful.

## Ready-made configs

- **Sunset** (gradient, plane): `(defaults)` · [preview](https://www.shaderz.fun/editor)
- **Ocean** (gradient, water): `sh=water&c1=0b3d91&c2=1fb6ff&c3=7df9ff&bg=020617&st=0.8&dn=1.6&cp=70` · [preview](https://www.shaderz.fun/editor?sh=water&c1=0b3d91&c2=1fb6ff&c3=7df9ff&bg=020617&st=0.8&dn=1.6&cp=70)
- **Orb** (gradient, sphere): `sh=sphere&c1=ffffff&c2=ffbb00&c3=0700ff&sp=0.1&st=1&cd=6&cp=75` · [preview](https://www.shaderz.fun/editor?sh=sphere&c1=ffffff&c2=ffbb00&c3=0700ff&sp=0.1&st=1&cd=6&cp=75)
- **Candy** (mesh): `s=mesh&c1=ff6ec7&c2=ffd166&c3=6ee7ff&bg=ffffff&st=1.5&gr=0.05` · [preview](https://www.shaderz.fun/editor?s=mesh&c1=ff6ec7&c2=ffd166&c3=6ee7ff&bg=ffffff&st=1.5&gr=0.05)
- **Northern** (aurora): `s=aurora&c1=22c55e&c2=06b6d4&c3=a855f7&bg=020617&dn=1.2` · [preview](https://www.shaderz.fun/editor?s=aurora&c1=22c55e&c2=06b6d4&c3=a855f7&bg=020617&dn=1.2)
- **Mercury** (liquid): `s=liquid&c1=e5e7eb&c2=6b7280&c3=f9fafb&bg=111827&st=1.4&dn=1.3&gr=0.1` · [preview](https://www.shaderz.fun/editor?s=liquid&c1=e5e7eb&c2=6b7280&c3=f9fafb&bg=111827&st=1.4&dn=1.3&gr=0.1)
- **Lava** (blobs): `s=blobs&c1=f97316&c2=ef4444&c3=facc15&bg=1c0a00&dn=1.4` · [preview](https://www.shaderz.fun/editor?s=blobs&c1=f97316&c2=ef4444&c3=facc15&bg=1c0a00&dn=1.4)

## Attributes

| Attribute | Effect |
| --- | --- |
| `data-shaderz` | Config (query string, full Shaderz URL, or JSON object). Changing it updates the background live. Removing it removes the background. |
| `data-shaderz-motion="always"` | Animate even when the user prefers reduced motion. Default is `auto`. |
| `data-shaderz-dpr="1"` | Max device pixel ratio. Default `2`. Lower it on heavy pages. |
| `data-shaderz-paused` | Render a still frame. Remove the attribute to resume. |

## JavaScript API

The script exposes `window.Shaderz`:

~~~js
const bg = Shaderz.mount(document.querySelector("#hero"), "s=mesh&c1=ff6ec7", { motion: "auto", dpr: 2 });
bg.set({ c1: "#00ff99", speed: 0.8 }); // merge
bg.replace("s=aurora");                  // reset to defaults + config
bg.pause(); bg.play();
bg.destroy();

Shaderz.parse("s=blobs&sp=1");           // -> full params object
Shaderz.refresh();                       // rescan the DOM for [data-shaderz]
~~~

## Behavior

- Renders with WebGL2 into a `<canvas>` inserted as the first child of the element, with `position:absolute; inset:0; z-index:-1; pointer-events:none` and `aria-hidden="true"`. The element gets `isolation:isolate`, and `position:relative` if it was static, so the canvas stays behind its content.
- Pauses when the element is off screen or the tab is hidden.
- Respects `prefers-reduced-motion` with a still frame.
- Without WebGL2, falls back to a static CSS gradient of c1, c2 and c3.
- Elements added later (SPA navigation, client rendering) are mounted automatically. Removed elements are cleaned up.

## Troubleshooting

- **Nothing shows**: the element has no height. Give it a height or `min-height`.
- **Canvas covers the content**: a parent sets `overflow` or `z-index` in a way that breaks stacking. Put the attribute on an empty `position:absolute; inset:0` div inside the section.
- **Colors ignored**: check the hex has 6 digits. Short hex like `fff` is not supported.
- **Hydration warning in React**: load the script after hydration (`next/script` with `afterInteractive`), and use an empty div.
