diff --git a/README.md b/README.md
index 5267525..893c897 100644
--- a/README.md
+++ b/README.md
@@ -1,113 +1,38 @@
# react-native-effects
-https://github.com/user-attachments/assets/5141208a-655a-4de8-94fb-3e66351bf36f
+WebGPU shader effects for React Native. Drop in a component, or write your own effect in WGSL. Rendering runs on a separate JS runtime, so a busy JS thread does not stall the animation.
-> **Experimental** — APIs may change without notice. Relies on `react-native-worklets` bundle mode, which is not enabled by default yet.
+
+
+
-WebGPU-powered effects running on **background thread** in React Native.
+> **Experimental.** APIs may change without notice. The library relies on `react-native-worklets` bundle mode, which is off by default for now.
-## Features
-
-- **WebGPU rendering** via `react-native-webgpu`
-- **Off-thread rendering** using `react-native-worklets` bundle mode — the GPU render loop runs on a separate JS runtime, keeping the main thread free
-- **Drop-in components** — use like any React Native `View`
-- **Customizable** — control colors, speed, intensity, and effect-specific parameters
-- **Animated & static** modes for gradients
-- **Build your own** — create custom effects with `ShaderView` and WGSL shaders
-
-## Components
-
-| Component | Description |
-| ------------------ | ---------------------------------------------- |
-| `Iridescence` | Mesmerizing iridescent animated effect |
-| `LiquidChrome` | Fluid metallic surface |
-| `Silk` | Smooth flowing silk fabric |
-| `Campfire` | Fire with drifting sparks and smoke |
-| `CalicoSwirl` | Warped noise pattern with flowing colors |
-| `Aurora` | Northern lights with flowing curtains of light |
-| `LinearGradient` | Smooth linear gradients (static & animated) |
-| `CircularGradient` | Customizable circular/radial gradients |
-
-## ShaderView
-
-`ShaderView` is the core building block that powers every effect in this library. It takes a WGSL fragment shader and renders it on a WebGPU canvas, handling the render loop, uniform buffer, and React Native view integration for you.
+## Quick look
```tsx
-import { ShaderView } from 'react-native-effects';
-
-;
-```
-
-| Prop | Type | Default | Description |
-| ---------------------- | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------- |
-| `fragmentShader` | `string` | — | WGSL fragment shader source |
-| `colors` | `ColorInput[]` | `[]` | Up to 2 colors mapped to `u.color0` and `u.color1` |
-| `params` | `number[]` | `[]` | Up to 8 floats mapped to `u.params0.xyzw` and `u.params1.xyzw` |
-| `speed` | `number` | `1.0` | Animation speed multiplier |
-| `isStatic` | `boolean` | `false` | Render once then stop the animation loop |
-| `transparent` | `boolean` | `false` | Clear the canvas to alpha `0` for an overlay-friendly transparent background |
-| `paramsSynchronizable` | `ParamsSynchronizable` | — | Live 4-float input written into the dedicated `u.live` slot every frame (touch/scroll/audio). See below |
-
-All built-in effects (Silk, Aurora, Campfire, etc.) are thin wrappers around `ShaderView`. You can use it directly to create your own custom effects — see the [Custom Effects Guide](CUSTOM_EFFECTS.md) for a full walkthrough and a ready-to-use AI prompt.
-
-### Live input with `paramsSynchronizable`
-
-Static `params` are great for values that change on the JS thread occasionally, but the render loop runs off-thread — so feeding it fast, per-frame input (a finger drag, scroll progress, audio level) through React props would be laggy. `paramsSynchronizable` is the bridge: a 4-float [Synchronizable](https://docs.swmansion.com/react-native-worklets/docs/synchronization/synchronizable) that the off-thread render loop reads every frame and writes into its own dedicated `u.live` slot — so it never collides with the static `params` (you keep all 8 _and_ get a live channel).
+import { StyleSheet } from 'react-native';
+import { Aurora } from 'react-native-effects';
-Create one with the `useParamsSynchronizable` hook and update it from your gesture or scroll handlers:
-
-```tsx
-import { ShaderView, useParamsSynchronizable } from 'react-native-effects';
-
-function TouchReactive() {
- // initial resting value, read once: (x, y, active, extra)
- const { paramsSynchronizable, setParamsSynchronizable } =
- useParamsSynchronizable([0.5, 0.5, 0, 0]);
-
- return (
- {
- const { locationX, locationY } = e.nativeEvent;
- setParamsSynchronizable(locationX, locationY, 1, 0);
- }}
- />
- );
+export function Background() {
+ return ;
}
```
-Inside the shader, declare the `live` field on the `Uniforms` struct (right after `params1`) and read the live values from `u.live`:
-
-```wgsl
-let pointer = u.live.xy; // (x, y) you wrote
-let active = u.live.z; // 1 while touching, 0 otherwise
-```
-
-`setParamsSynchronizable(x, y, active, extra)` runs on the JS thread; the four floats are by convention `(x, y, active, extra)` for pointer input or `(progress, …)` for scroll-driven effects, but the meaning is entirely up to your shader. For a ready-made pan-gesture variant, use [`ShaderViewWithPanGesture`](src/components/ShaderViewWithPanGesture/index.tsx).
+Effects accept standard `View` props, so they size and layer like any other view.
## Installation
```sh
npm install react-native-effects
+npm install react-native-webgpu react-native-worklets react-native-gesture-handler
```
-### Peer dependencies
+Then complete the two steps below. The example app runs on React Native 0.88, Expo 58, `react-native-webgpu` 0.17 and `react-native-worklets` 0.13.
-```sh
-npm install react-native-webgpu react-native-worklets react-native-reanimated react-native-gesture-handler
-```
+### Android API level
-### Android requirements
-
-`react-native-webgpu` uses `AHardwareBuffer` APIs that require **Android API 26+**, so your app must set `minSdkVersion` to at least `26` (the default in many templates is `24`). In an Expo project, use [`expo-build-properties`](https://docs.expo.dev/versions/latest/sdk/build-properties/):
+`react-native-webgpu` uses `AHardwareBuffer` APIs that require **Android API 26+**, and many templates default to 24. In a bare project, set `minSdkVersion = 26` in `android/build.gradle`. In Expo, use [`expo-build-properties`](https://docs.expo.dev/versions/latest/sdk/build-properties/):
```json
{
@@ -119,24 +44,9 @@ npm install react-native-webgpu react-native-worklets react-native-reanimated re
}
```
-In a bare React Native project, set `minSdkVersion = 26` in `android/build.gradle`.
-
-### Bundle mode setup
+### Bundle mode
-This library relies on `react-native-worklets` [Bundle Mode](https://docs.swmansion.com/react-native-worklets/docs/bundleMode). You need to configure Metro, Babel, and package.json in your app.
-
-**package.json** (add at root level)
-
-```json
-{
- "worklets": {
- "staticFeatureFlags": {
- "BUNDLE_MODE_ENABLED": true,
- "FETCH_PREVIEW_ENABLED": true
- }
- }
-}
-```
+The library needs `react-native-worklets` [Bundle Mode](https://docs.swmansion.com/react-native-worklets/docs/bundleMode). Enable it in Babel and Metro:
Bare React Native
@@ -155,7 +65,7 @@ module.exports = {
**metro.config.js**
```js
-const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
+const { getDefaultConfig } = require('@react-native/metro-config');
const {
getBundleModeMetroConfig,
} = require('react-native-worklets/bundleMode');
@@ -181,7 +91,7 @@ module.exports = config;
Expo
-Install additional dev dependencies:
+Install the additional dev dependencies:
```sh
npm install -D babel-preset-expo @react-native/metro-config
@@ -229,78 +139,107 @@ config.transformer = {
module.exports = config;
```
-
-
-## Usage
+Release builds on Expo also need the `require.getModules` polyfill: copy [`metro-get-modules-polyfill.js`](example/metro-get-modules-polyfill.js) and register it the way [`example/metro.config.js`](example/metro.config.js) does.
-```tsx
-import { Iridescence, LiquidChrome, Aurora } from 'react-native-effects';
-
-// Full-screen animated background
-
-
-// Metallic effect with custom speed
-
-
-// Aurora borealis with custom parameters
-
-```
+
-### Common Props
+## Effects
-All shader components accept standard `View` props plus:
+The package exports eight ready-made components. Colors are `ColorInput` values: color strings or numbers.
-| Prop | Type | Default | Description |
-| ------- | ------------------ | ------- | -------------------------- |
-| `color` | `string \| number` | varies | Base tint color |
-| `speed` | `number` | `1.0` | Animation speed multiplier |
+### Animated backgrounds
-### Aurora
+All of these take `color` and `speed` (a multiplier, default `1.0`), plus:
-| Prop | Type | Default | Description |
-| ----------- | -------- | ------- | ------------------------------ |
-| `intensity` | `number` | `1.0` | Brightness of the aurora bands |
-| `layers` | `number` | `3` | Number of curtain layers (1-5) |
-| `waviness` | `number` | `1.0` | Turbulence of the curtains |
+| Component | Looks like | Extra props |
+| -------------- | ----------------------------------- | ---------------------------------------------- |
+| `Aurora` | Northern lights | `intensity`, `layers` (1-5), `waviness` |
+| `CalicoSwirl` | Warped noise with flowing colors | `intensity` |
+| `Campfire` | Fire with drifting sparks and smoke | `sparkSize`, `fireIntensity`, `smokeIntensity` |
+| `Iridescence` | Soap-film color | none |
+| `LiquidChrome` | Fluid metallic surface | `amplitude`, `frequencyX`, `frequencyY` |
+| `Silk` | Smooth flowing fabric | `scale`, `rotation`, `noiseIntensity` |
### Gradients
```tsx
-import { LinearGradient, CircularGradient } from 'react-native-effects';
+import { CircularGradient, LinearGradient } from 'react-native-effects';
```
-## Create Your Own Effect
+| Component | Required props | Optional props |
+| ------------------ | --------------------------------- | --------------------------------------------------- |
+| `LinearGradient` | `startColor`, `endColor`, `angle` | `speed` in degrees per second, `0` is static |
+| `CircularGradient` | `centerColor` | `edgeColor`, `centerX`, `centerY`, `sizeX`, `sizeY` |
+
+## Build your own
+
+Every effect above is a thin wrapper around `ShaderView`, which takes a WGSL fragment shader and handles the WebGPU canvas, render loop and uniform buffer.
+
+```tsx
+import { ShaderView } from 'react-native-effects';
+
+;
+```
+
+| Prop | Type | Default | Description |
+| ---------------------- | ---------------------- | ------- | -------------------------------------------------------------------- |
+| `fragmentShader` | `string` | none | WGSL fragment shader source |
+| `colors` | `ColorInput[]` | `[]` | Up to 2 colors, mapped to `u.color0` and `u.color1` |
+| `params` | `number[]` | `[]` | Up to 8 floats, mapped to `u.params0.xyzw` and `u.params1.xyzw` |
+| `speed` | `number` | `1.0` | Animation speed multiplier |
+| `isStatic` | `boolean` | `false` | Render once, then stop the animation loop |
+| `transparent` | `boolean` | `false` | Clear to alpha `0`, for overlays |
+| `texture` | `ImageSourcePropType` | none | Image the shader can sample, for effects on top of real photos |
+| `paramsSynchronizable` | `ParamsSynchronizable` | none | Live floats written to `u.live` every frame, independent of `params` |
+
+### Live input
+
+React props are too slow for per-frame input such as a finger drag or an audio level. `ShaderViewWithPanGesture` feeds touch straight to the render loop: `u.live.xy` is the pointer in UV space and `u.live.z` is `1` while touching.
+
+```tsx
+import { ShaderViewWithPanGesture } from 'react-native-effects';
+
+;
+```
+
+For scroll, audio or any other source, create your own channel with `useParamsSynchronizable` and pass it as `paramsSynchronizable`.
+
+The [Custom Effects Guide](CUSTOM_EFFECTS.md) covers the uniform layout, the shader contract and live input in full, and includes a prompt you can paste into an AI assistant to generate an effect.
-Want to build a custom shader effect? Check out the [Custom Effects Guide](CUSTOM_EFFECTS.md) — it includes everything you need to know about the `ShaderView` API, the uniform layout, and the WGSL shader contract. It also has a ready-to-use AI prompt you can paste into ChatGPT or Claude to generate a complete custom effect.
+## Example app
-## Running the example app
+The clip above is the [example app](example), a catalog of 45 effects built with `ShaderView`. Most of them, including everything in the clip except Liquid Chrome, are demos in `example/src`. The package does not export them, so treat them as source to copy from. Many react to tilt, touch, sound or the magnetometer.
```sh
yarn install
-yarn prebuild # generates native iOS/Android projects
-yarn ios # run on iOS simulator
-yarn android # run on Android emulator
+yarn example prebuild
+yarn example ios # or: yarn example android
```
-To start fresh after config changes, use `yarn prebuild:clean` instead of `yarn prebuild`.
+Use `yarn example prebuild:clean` to start fresh after config changes. The app's photo and software credits are in [docs/credits.md](docs/credits.md).
## Contributing
diff --git a/docs/media/demo.webp b/docs/media/demo.webp
new file mode 100644
index 0000000..905bf16
Binary files /dev/null and b/docs/media/demo.webp differ