diff --git a/.github/workflows/pages.yml b/.github/workflows/pages.yml
index 7111928..caf159d 100644
--- a/.github/workflows/pages.yml
+++ b/.github/workflows/pages.yml
@@ -24,42 +24,17 @@ jobs:
persist-credentials: false
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
- node-version: 20
+ node-version: 20.19.0
cache: npm
- run: npm ci
- run: npm run build
+ - run: npm run build:playground
- name: Build static playground artifact
run: |
mkdir -p _site
- cp -R playground dist _site/
+ cp -R dist-playground/* _site/
cp grain-gradient-og.png _site/screenshot.png
touch _site/.nojekyll
- cat > _site/index.html <<'HTML'
-
-
-
-
-
-
- grain-gradient playground
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- Open playground
-
-
- HTML
- uses: actions/configure-pages@983d7736d9b0ae728b81ab479565c72886d7745b
- uses: actions/upload-pages-artifact@56afc609e74202658d3ffba0e8f6dda462b719fa
with:
diff --git a/.github/workflows/quality.yml b/.github/workflows/quality.yml
index 7e9d061..26c703f 100644
--- a/.github/workflows/quality.yml
+++ b/.github/workflows/quality.yml
@@ -23,7 +23,7 @@ jobs:
- uses: actions/setup-node@49933ea5288caeca8642d1e84afbd3f7d6820020
with:
- node-version: 20
+ node-version: 20.19.0
cache: npm
- run: npm ci
diff --git a/.gitignore b/.gitignore
index 0ca39c0..5e47a8b 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,5 @@
node_modules
dist
+dist-playground
.DS_Store
+.slim/deepwork/
diff --git a/README.md b/README.md
index bdc6a86..58503b3 100644
--- a/README.md
+++ b/README.md
@@ -1,10 +1,12 @@
# grain-gradient
-Lightweight TypeScript helpers for mesh + grain gradients.
+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.

-[Open the playground](https://aomona.github.io/grain-gradient/playground/)
+[Open the playground](https://aomona.github.io/grain-gradient/)
## Installation
@@ -12,120 +14,79 @@ Lightweight TypeScript helpers for mesh + grain gradients.
npm i grain-gradient
```
-## Core CSS
+## WebGL shader renderer
-```ts
-import { createGrainGradientCSS, presets } from "grain-gradient";
-
-const css = createGrainGradientCSS({
- ...presets["Aurora Citrus"],
- motionPreset: "drift",
- motionSpeed: 38,
- motionIntensity: 46,
- swirl: 30,
-});
-```
-
-`grain-gradient` has no runtime dependencies. The core entry does not import React.
-
-The core API, playground, and React helper can switch to a Canvas-generated PNG grain fallback for Android Chrome device testing. The fallback helpers are SSR-safe: SVG grain is rendered first, then Canvas grain can be applied after hydration when Android Chrome is detected.
-
-```ts
-import { createAndroidCanvasFallbackStyle } from "grain-gradient";
-
-const fallback = createAndroidCanvasFallbackStyle({ androidCanvasFallback: "auto" });
-if (fallback) Object.assign(grainLayer.style, fallback);
-```
-
-`auto` is resolved where the helper runs. If you are exporting static CSS on a non-Android browser and want the Canvas fallback included, use `androidCanvasFallback: "on"` for that export.
-
-For CSS generated with `createGrainGradientCSS()`, apply those values to the generated `::after` grain layer as a CSS override.
-
-See [API reference](./docs/API.md) for all core functions, React helpers, options, and presets.
-
-## React
+`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.
```tsx
-import { GrainGradient } from "grain-gradient/react";
+import { GrainGradient, presets } from "grain-gradient/react";
export function Hero() {
return (
);
}
```
-For SSR frameworks, pass the request user agent as a hint so `auto` can use the same Android Chrome detection after hydration:
+The component creates a `