react-native-effects 0.1.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -13
- package/lib/module/components/ShaderView/index.js +122 -27
- package/lib/module/components/ShaderView/index.js.map +1 -1
- package/lib/module/components/ShaderViewWithPanGesture/index.js +196 -0
- package/lib/module/components/ShaderViewWithPanGesture/index.js.map +1 -0
- package/lib/module/hooks/useParamsSynchronizable.js +37 -0
- package/lib/module/hooks/useParamsSynchronizable.js.map +1 -0
- package/lib/module/hooks/useWGPUSetup.js +62 -13
- package/lib/module/hooks/useWGPUSetup.js.map +1 -1
- package/lib/module/index.js +3 -1
- package/lib/module/index.js.map +1 -1
- package/lib/module/shaders/uniforms.js +4 -3
- package/lib/module/shaders/uniforms.js.map +1 -1
- package/lib/module/utils/gpuDevice.js +38 -0
- package/lib/module/utils/gpuDevice.js.map +1 -0
- package/lib/typescript/src/components/Aurora.d.ts +1 -1
- package/lib/typescript/src/components/Aurora.d.ts.map +1 -1
- package/lib/typescript/src/components/CalicoSwirl.d.ts +1 -1
- package/lib/typescript/src/components/CalicoSwirl.d.ts.map +1 -1
- package/lib/typescript/src/components/Campfire.d.ts +1 -1
- package/lib/typescript/src/components/Campfire.d.ts.map +1 -1
- package/lib/typescript/src/components/CircularGradient.d.ts +1 -1
- package/lib/typescript/src/components/CircularGradient.d.ts.map +1 -1
- package/lib/typescript/src/components/Iridescence.d.ts +1 -1
- package/lib/typescript/src/components/Iridescence.d.ts.map +1 -1
- package/lib/typescript/src/components/LinearGradient.d.ts +1 -1
- package/lib/typescript/src/components/LinearGradient.d.ts.map +1 -1
- package/lib/typescript/src/components/LiquidChrome.d.ts +1 -1
- package/lib/typescript/src/components/LiquidChrome.d.ts.map +1 -1
- package/lib/typescript/src/components/ShaderView/index.d.ts +1 -1
- package/lib/typescript/src/components/ShaderView/index.d.ts.map +1 -1
- package/lib/typescript/src/components/ShaderView/types.d.ts +20 -0
- package/lib/typescript/src/components/ShaderView/types.d.ts.map +1 -1
- package/lib/typescript/src/components/ShaderViewWithPanGesture/index.d.ts +35 -0
- package/lib/typescript/src/components/ShaderViewWithPanGesture/index.d.ts.map +1 -0
- package/lib/typescript/src/components/Silk.d.ts +1 -1
- package/lib/typescript/src/components/Silk.d.ts.map +1 -1
- package/lib/typescript/src/hooks/useParamsSynchronizable.d.ts +22 -0
- package/lib/typescript/src/hooks/useParamsSynchronizable.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useWGPUSetup.d.ts +5 -2
- package/lib/typescript/src/hooks/useWGPUSetup.d.ts.map +1 -1
- package/lib/typescript/src/index.d.ts +6 -2
- package/lib/typescript/src/index.d.ts.map +1 -1
- package/lib/typescript/src/shaders/uniforms.d.ts +3 -3
- package/lib/typescript/src/shaders/uniforms.d.ts.map +1 -1
- package/lib/typescript/src/utils/gpuDevice.d.ts +13 -0
- package/lib/typescript/src/utils/gpuDevice.d.ts.map +1 -0
- package/package.json +31 -30
- package/src/components/ShaderView/index.tsx +140 -32
- package/src/components/ShaderView/types.ts +21 -0
- package/src/components/ShaderViewWithPanGesture/index.tsx +225 -0
- package/src/hooks/useParamsSynchronizable.ts +52 -0
- package/src/hooks/useWGPUSetup.tsx +69 -21
- package/src/index.tsx +10 -1
- package/src/shaders/uniforms.ts +4 -3
- package/src/utils/gpuDevice.ts +38 -0
- package/lib/module/utils/initWebGPU.js +0 -40
- package/lib/module/utils/initWebGPU.js.map +0 -1
- package/lib/typescript/src/utils/initWebGPU.d.ts +0 -23
- package/lib/typescript/src/utils/initWebGPU.d.ts.map +0 -1
- package/src/utils/initWebGPU.ts +0 -47
package/README.md
CHANGED
|
@@ -4,11 +4,11 @@ https://github.com/user-attachments/assets/5141208a-655a-4de8-94fb-3e66351bf36f
|
|
|
4
4
|
|
|
5
5
|
> **Experimental** — APIs may change without notice. Relies on `react-native-worklets` bundle mode, which is not enabled by default yet.
|
|
6
6
|
|
|
7
|
-
WebGPU-powered effects running on **background thread** in React Native.
|
|
7
|
+
WebGPU-powered effects running on **background thread** in React Native.
|
|
8
8
|
|
|
9
9
|
## Features
|
|
10
10
|
|
|
11
|
-
- **WebGPU rendering** via `react-native-
|
|
11
|
+
- **WebGPU rendering** via `react-native-webgpu`
|
|
12
12
|
- **Off-thread rendering** using `react-native-worklets` bundle mode — the GPU render loop runs on a separate JS runtime, keeping the main thread free
|
|
13
13
|
- **Drop-in components** — use like any React Native `View`
|
|
14
14
|
- **Customizable** — control colors, speed, intensity, and effect-specific parameters
|
|
@@ -44,16 +44,55 @@ import { ShaderView } from 'react-native-effects';
|
|
|
44
44
|
/>;
|
|
45
45
|
```
|
|
46
46
|
|
|
47
|
-
| Prop
|
|
48
|
-
|
|
|
49
|
-
| `fragmentShader`
|
|
50
|
-
| `colors`
|
|
51
|
-
| `params`
|
|
52
|
-
| `speed`
|
|
53
|
-
| `isStatic`
|
|
47
|
+
| Prop | Type | Default | Description |
|
|
48
|
+
| ---------------------- | ---------------------- | ------- | ------------------------------------------------------------------------------------------------------- |
|
|
49
|
+
| `fragmentShader` | `string` | — | WGSL fragment shader source |
|
|
50
|
+
| `colors` | `ColorInput[]` | `[]` | Up to 2 colors mapped to `u.color0` and `u.color1` |
|
|
51
|
+
| `params` | `number[]` | `[]` | Up to 8 floats mapped to `u.params0.xyzw` and `u.params1.xyzw` |
|
|
52
|
+
| `speed` | `number` | `1.0` | Animation speed multiplier |
|
|
53
|
+
| `isStatic` | `boolean` | `false` | Render once then stop the animation loop |
|
|
54
|
+
| `transparent` | `boolean` | `false` | Clear the canvas to alpha `0` for an overlay-friendly transparent background |
|
|
55
|
+
| `paramsSynchronizable` | `ParamsSynchronizable` | — | Live 4-float input written into the dedicated `u.live` slot every frame (touch/scroll/audio). See below |
|
|
54
56
|
|
|
55
57
|
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.
|
|
56
58
|
|
|
59
|
+
### Live input with `paramsSynchronizable`
|
|
60
|
+
|
|
61
|
+
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).
|
|
62
|
+
|
|
63
|
+
Create one with the `useParamsSynchronizable` hook and update it from your gesture or scroll handlers:
|
|
64
|
+
|
|
65
|
+
```tsx
|
|
66
|
+
import { ShaderView, useParamsSynchronizable } from 'react-native-effects';
|
|
67
|
+
|
|
68
|
+
function TouchReactive() {
|
|
69
|
+
// initial resting value, read once: (x, y, active, extra)
|
|
70
|
+
const { paramsSynchronizable, setParamsSynchronizable } =
|
|
71
|
+
useParamsSynchronizable([0.5, 0.5, 0, 0]);
|
|
72
|
+
|
|
73
|
+
return (
|
|
74
|
+
<ShaderView
|
|
75
|
+
fragmentShader={myShader}
|
|
76
|
+
paramsSynchronizable={paramsSynchronizable}
|
|
77
|
+
style={{ width: '100%', height: 300 }}
|
|
78
|
+
onTouchMove={(e) => {
|
|
79
|
+
const { locationX, locationY } = e.nativeEvent;
|
|
80
|
+
setParamsSynchronizable(locationX, locationY, 1, 0);
|
|
81
|
+
}}
|
|
82
|
+
/>
|
|
83
|
+
);
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
Inside the shader, declare the `live` field on the `Uniforms` struct (right after `params1`) and read the live values from `u.live`:
|
|
88
|
+
|
|
89
|
+
```wgsl
|
|
90
|
+
let pointer = u.live.xy; // (x, y) you wrote
|
|
91
|
+
let active = u.live.z; // 1 while touching, 0 otherwise
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
`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).
|
|
95
|
+
|
|
57
96
|
## Installation
|
|
58
97
|
|
|
59
98
|
```sh
|
|
@@ -63,9 +102,25 @@ npm install react-native-effects
|
|
|
63
102
|
### Peer dependencies
|
|
64
103
|
|
|
65
104
|
```sh
|
|
66
|
-
npm install react-native-
|
|
105
|
+
npm install react-native-webgpu react-native-worklets react-native-reanimated react-native-gesture-handler
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
### Android requirements
|
|
109
|
+
|
|
110
|
+
`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/):
|
|
111
|
+
|
|
112
|
+
```json
|
|
113
|
+
{
|
|
114
|
+
"expo": {
|
|
115
|
+
"plugins": [
|
|
116
|
+
["expo-build-properties", { "android": { "minSdkVersion": 26 } }]
|
|
117
|
+
]
|
|
118
|
+
}
|
|
119
|
+
}
|
|
67
120
|
```
|
|
68
121
|
|
|
122
|
+
In a bare React Native project, set `minSdkVersion = 26` in `android/build.gradle`.
|
|
123
|
+
|
|
69
124
|
### Bundle mode setup
|
|
70
125
|
|
|
71
126
|
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.
|
|
@@ -101,7 +156,9 @@ module.exports = {
|
|
|
101
156
|
|
|
102
157
|
```js
|
|
103
158
|
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
|
|
104
|
-
const {
|
|
159
|
+
const {
|
|
160
|
+
getBundleModeMetroConfig,
|
|
161
|
+
} = require('react-native-worklets/bundleMode');
|
|
105
162
|
|
|
106
163
|
let config = getDefaultConfig(__dirname);
|
|
107
164
|
config = getBundleModeMetroConfig(config);
|
|
@@ -138,7 +195,10 @@ module.exports = function (api) {
|
|
|
138
195
|
return {
|
|
139
196
|
presets: ['babel-preset-expo'],
|
|
140
197
|
plugins: [
|
|
141
|
-
[
|
|
198
|
+
[
|
|
199
|
+
'react-native-worklets/plugin',
|
|
200
|
+
{ bundleMode: true, strictGlobal: true },
|
|
201
|
+
],
|
|
142
202
|
],
|
|
143
203
|
};
|
|
144
204
|
};
|
|
@@ -148,7 +208,9 @@ module.exports = function (api) {
|
|
|
148
208
|
|
|
149
209
|
```js
|
|
150
210
|
const { getDefaultConfig } = require('expo/metro-config');
|
|
151
|
-
const {
|
|
211
|
+
const {
|
|
212
|
+
getBundleModeMetroConfig,
|
|
213
|
+
} = require('react-native-worklets/bundleMode');
|
|
152
214
|
|
|
153
215
|
/** @type {import('expo/metro-config').MetroConfig} */
|
|
154
216
|
let config = getDefaultConfig(__dirname);
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
|
|
3
|
-
import { PixelRatio, StyleSheet } from 'react-native';
|
|
4
|
-
import { Canvas } from 'react-native-
|
|
5
|
-
import { useEffect, useRef } from 'react';
|
|
3
|
+
import { AppState, PixelRatio, StyleSheet } from 'react-native';
|
|
4
|
+
import { Canvas, installWebGPU } from 'react-native-webgpu';
|
|
5
|
+
import { useEffect, useRef, useState } from 'react';
|
|
6
6
|
import { createSynchronizable, scheduleOnRuntime } from 'react-native-worklets';
|
|
7
7
|
import { colorToVec4 } from "../../utils/colors.js";
|
|
8
8
|
import { useWGPUSetup } from "../../hooks/useWGPUSetup.js";
|
|
@@ -21,14 +21,30 @@ export default function ShaderView({
|
|
|
21
21
|
speed = 1.0,
|
|
22
22
|
params = [],
|
|
23
23
|
isStatic = false,
|
|
24
|
+
transparent = false,
|
|
25
|
+
paramsSynchronizable,
|
|
24
26
|
style,
|
|
25
27
|
...viewProps
|
|
26
28
|
}) {
|
|
27
29
|
const {
|
|
28
30
|
canvasRef,
|
|
29
31
|
runtime,
|
|
30
|
-
resources
|
|
32
|
+
resources,
|
|
33
|
+
onCanvasLayout
|
|
31
34
|
} = useWGPUSetup();
|
|
35
|
+
|
|
36
|
+
// Pause the render loop while the app is backgrounded. The rAF loop otherwise
|
|
37
|
+
// keeps churning frames against a surface that's offscreen (and often
|
|
38
|
+
// transiently invalid), wasting battery/GPU. We only pause on a true
|
|
39
|
+
// 'background' transition — iOS 'inactive' (app switcher peek, notification
|
|
40
|
+
// pulldown) is left running to avoid flicker on brief, foreground interruptions.
|
|
41
|
+
const [appActive, setAppActive] = useState(() => (AppState.currentState ?? 'active') !== 'background');
|
|
42
|
+
useEffect(() => {
|
|
43
|
+
const subscription = AppState.addEventListener('change', state => {
|
|
44
|
+
setAppActive(state !== 'background');
|
|
45
|
+
});
|
|
46
|
+
return () => subscription.remove();
|
|
47
|
+
}, []);
|
|
32
48
|
const propsSync = useRef(createSynchronizable(new Float64Array(SYNC_SIZE))).current;
|
|
33
49
|
|
|
34
50
|
// Convert props to flat floats and push to synchronizable
|
|
@@ -76,9 +92,12 @@ export default function ShaderView({
|
|
|
76
92
|
};
|
|
77
93
|
}, [propsSync]);
|
|
78
94
|
|
|
79
|
-
// Start render loop when GPU resources are ready
|
|
95
|
+
// Start render loop when GPU resources are ready and the app is foregrounded.
|
|
96
|
+
// When the app backgrounds, `appActive` flips false and this effect's cleanup
|
|
97
|
+
// tears the loop down (via the `cancelled` token below); on return to the
|
|
98
|
+
// foreground it re-runs and starts a fresh loop.
|
|
80
99
|
useEffect(() => {
|
|
81
|
-
if (!resources) {
|
|
100
|
+
if (!resources || !appActive) {
|
|
82
101
|
return;
|
|
83
102
|
}
|
|
84
103
|
const {
|
|
@@ -87,9 +106,21 @@ export default function ShaderView({
|
|
|
87
106
|
presentationFormat
|
|
88
107
|
} = resources;
|
|
89
108
|
const dpr = PixelRatio.get();
|
|
109
|
+
|
|
110
|
+
// Per-run cancellation token. On Fast Refresh / dep change / unmount, React
|
|
111
|
+
// runs this effect's cleanup, which flips the flag and stops *this* loop —
|
|
112
|
+
// otherwise the old worklet RAF loop keeps running forever alongside the new
|
|
113
|
+
// one, stacking a duplicate render loop on every Metro reload.
|
|
114
|
+
const cancelled = createSynchronizable(new Float64Array(1));
|
|
90
115
|
scheduleOnRuntime(runtime, () => {
|
|
91
116
|
'worklet';
|
|
92
117
|
|
|
118
|
+
// Worklet runtimes start without the WebGPU flag constants
|
|
119
|
+
// (GPUBufferUsage, GPUTextureUsage, ...). installWebGPU() captures them
|
|
120
|
+
// into this runtime so they're available below. Idempotent / safe no-op
|
|
121
|
+
// if already installed.
|
|
122
|
+
installWebGPU();
|
|
123
|
+
|
|
93
124
|
// Create pipeline once
|
|
94
125
|
const pipeline = device.createRenderPipeline({
|
|
95
126
|
layout: 'auto',
|
|
@@ -130,9 +161,37 @@ export default function ShaderView({
|
|
|
130
161
|
const uniformData = new Float32Array(UNIFORM_FLOAT_COUNT);
|
|
131
162
|
let accumulatedTime = 0;
|
|
132
163
|
let lastTimestamp = 0;
|
|
164
|
+
let warned = false;
|
|
165
|
+
let bufferDestroyed = false;
|
|
166
|
+
|
|
167
|
+
// Free this loop's uniform buffer when the loop ends (alive=0 / superseded
|
|
168
|
+
// by Fast Refresh / unmount). On a fragmentShader change the effect
|
|
169
|
+
// re-runs and schedules a fresh loop with a new buffer while the device
|
|
170
|
+
// persists, so without this the old buffer leaks every shader swap.
|
|
171
|
+
function destroyBuffer() {
|
|
172
|
+
if (bufferDestroyed) {
|
|
173
|
+
return;
|
|
174
|
+
}
|
|
175
|
+
bufferDestroyed = true;
|
|
176
|
+
try {
|
|
177
|
+
uniformBuffer.destroy();
|
|
178
|
+
} catch {
|
|
179
|
+
// The device may already have been destroyed on unmount — the buffer
|
|
180
|
+
// is gone either way, so there's nothing to recover.
|
|
181
|
+
return;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
133
184
|
function render(timestamp) {
|
|
134
185
|
const props = propsSync.getDirty();
|
|
135
186
|
if (props[IDX_ALIVE] === 0) {
|
|
187
|
+
destroyBuffer();
|
|
188
|
+
return;
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
// This loop was superseded (Fast Refresh / unmount) — bail without
|
|
192
|
+
// scheduling another frame so it can be garbage-collected.
|
|
193
|
+
if (cancelled.getDirty()[0] === 1) {
|
|
194
|
+
destroyBuffer();
|
|
136
195
|
return;
|
|
137
196
|
}
|
|
138
197
|
|
|
@@ -150,7 +209,7 @@ export default function ShaderView({
|
|
|
150
209
|
const height = canvas.height || 1;
|
|
151
210
|
const aspect = width / height;
|
|
152
211
|
|
|
153
|
-
// Fill uniform data (
|
|
212
|
+
// Fill uniform data (7 × vec4 = 28 floats)
|
|
154
213
|
// resolution: vec4<f32>
|
|
155
214
|
uniformData[0] = width;
|
|
156
215
|
uniformData[1] = height;
|
|
@@ -181,39 +240,75 @@ export default function ShaderView({
|
|
|
181
240
|
uniformData[18] = props[IDX_PARAMS + 2];
|
|
182
241
|
uniformData[19] = props[IDX_PARAMS + 3];
|
|
183
242
|
|
|
184
|
-
// params1: vec4<f32>
|
|
243
|
+
// params1: vec4<f32> — static params[4..7]
|
|
185
244
|
uniformData[20] = props[IDX_PARAMS + 4];
|
|
186
245
|
uniformData[21] = props[IDX_PARAMS + 5];
|
|
187
246
|
uniformData[22] = props[IDX_PARAMS + 6];
|
|
188
247
|
uniformData[23] = props[IDX_PARAMS + 7];
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
248
|
+
|
|
249
|
+
// live: vec4<f32> — off-thread input (touch/scroll/audio) from
|
|
250
|
+
// paramsSynchronizable, written into its own slot so it never collides
|
|
251
|
+
// with the static params. Stays (0,0,0,0) when no channel is attached.
|
|
252
|
+
if (paramsSynchronizable) {
|
|
253
|
+
const live = paramsSynchronizable.getDirty();
|
|
254
|
+
uniformData[24] = live[0];
|
|
255
|
+
uniformData[25] = live[1];
|
|
256
|
+
uniformData[26] = live[2];
|
|
257
|
+
uniformData[27] = live[3];
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// GPU work can throw when the surface is transiently invalid — the app
|
|
261
|
+
// backgrounded, the view detached, or the device was lost. Swallow the
|
|
262
|
+
// failed frame so the loop survives and recovers when the surface comes
|
|
263
|
+
// back (rather than the worklet crashing or the loop dying silently).
|
|
264
|
+
try {
|
|
265
|
+
device.queue.writeBuffer(uniformBuffer, 0, uniformData);
|
|
266
|
+
const commandEncoder = device.createCommandEncoder();
|
|
267
|
+
const textureView = context.getCurrentTexture().createView();
|
|
268
|
+
const passEncoder = commandEncoder.beginRenderPass({
|
|
269
|
+
colorAttachments: [{
|
|
270
|
+
view: textureView,
|
|
271
|
+
clearValue: transparent ? [0, 0, 0, 0] : [0, 0, 0, 1],
|
|
272
|
+
loadOp: 'clear',
|
|
273
|
+
storeOp: 'store'
|
|
274
|
+
}]
|
|
275
|
+
});
|
|
276
|
+
passEncoder.setPipeline(pipeline);
|
|
277
|
+
passEncoder.setBindGroup(0, bindGroup);
|
|
278
|
+
passEncoder.draw(3);
|
|
279
|
+
passEncoder.end();
|
|
280
|
+
device.queue.submit([commandEncoder.finish()]);
|
|
281
|
+
context.present();
|
|
282
|
+
} catch (e) {
|
|
283
|
+
// Warn once to avoid spamming the console every frame on a persistent
|
|
284
|
+
// failure (e.g. a lost device).
|
|
285
|
+
if (!warned) {
|
|
286
|
+
warned = true;
|
|
287
|
+
console.warn('[react-native-effects] render frame failed:', e);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
// Always reschedule animated loops, even after a caught failure, so the
|
|
292
|
+
// effect self-heals once the surface is valid again.
|
|
206
293
|
if (!isStatic) {
|
|
207
294
|
requestAnimationFrame(render);
|
|
208
295
|
}
|
|
209
296
|
}
|
|
210
297
|
requestAnimationFrame(render);
|
|
211
298
|
});
|
|
212
|
-
|
|
299
|
+
return () => {
|
|
300
|
+
cancelled.setBlocking(() => Float64Array.of(1));
|
|
301
|
+
};
|
|
302
|
+
}, [resources, appActive, runtime, propsSync, paramsSynchronizable, fragmentShader, isStatic, transparent]);
|
|
213
303
|
return /*#__PURE__*/_jsx(Canvas, {
|
|
214
304
|
ref: canvasRef,
|
|
305
|
+
transparent: transparent,
|
|
215
306
|
style: [styles.canvas, style],
|
|
216
|
-
...viewProps
|
|
307
|
+
...viewProps,
|
|
308
|
+
onLayout: event => {
|
|
309
|
+
onCanvasLayout(event);
|
|
310
|
+
viewProps.onLayout?.(event);
|
|
311
|
+
}
|
|
217
312
|
});
|
|
218
313
|
}
|
|
219
314
|
const styles = StyleSheet.create({
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"names":["PixelRatio","StyleSheet","Canvas","useEffect","useRef","createSynchronizable","scheduleOnRuntime","colorToVec4","useWGPUSetup","TRIANGLE_VERTEX_SHADER","UNIFORM_BUFFER_SIZE","UNIFORM_FLOAT_COUNT","jsx","_jsx","SYNC_SIZE","IDX_SPEED","IDX_PARAMS","IDX_ALIVE","ShaderView","fragmentShader","colors","speed","params","isStatic","style","viewProps","canvasRef","runtime","resources","propsSync","Float64Array","current","data","undefined","c0","r","g","b","a","c1","i","setBlocking","prev","device","context","presentationFormat","dpr","get","pipeline","createRenderPipeline","layout","vertex","module","createShaderModule","code","entryPoint","fragment","targets","format","primitive","topology","uniformBuffer","createBuffer","size","usage","GPUBufferUsage","UNIFORM","COPY_DST","bindGroup","createBindGroup","getBindGroupLayout","entries","binding","resource","buffer","uniformData","Float32Array","accumulatedTime","lastTimestamp","render","timestamp","props","getDirty","dt","currentSpeed","canvas","width","height","aspect","queue","writeBuffer","commandEncoder","createCommandEncoder","textureView","getCurrentTexture","createView","passEncoder","beginRenderPass","colorAttachments","view","clearValue","loadOp","storeOp","setPipeline","setBindGroup","draw","end","submit","finish","present","requestAnimationFrame","ref","styles","create","flex"],"sourceRoot":"../../../../src","sources":["components/ShaderView/index.tsx"],"mappings":";;AAAA,SAASA,UAAU,EAAEC,UAAU,QAAQ,cAAc;
|
|
1
|
+
{"version":3,"names":["AppState","PixelRatio","StyleSheet","Canvas","installWebGPU","useEffect","useRef","useState","createSynchronizable","scheduleOnRuntime","colorToVec4","useWGPUSetup","TRIANGLE_VERTEX_SHADER","UNIFORM_BUFFER_SIZE","UNIFORM_FLOAT_COUNT","jsx","_jsx","SYNC_SIZE","IDX_SPEED","IDX_PARAMS","IDX_ALIVE","ShaderView","fragmentShader","colors","speed","params","isStatic","transparent","paramsSynchronizable","style","viewProps","canvasRef","runtime","resources","onCanvasLayout","appActive","setAppActive","currentState","subscription","addEventListener","state","remove","propsSync","Float64Array","current","data","undefined","c0","r","g","b","a","c1","i","setBlocking","prev","device","context","presentationFormat","dpr","get","cancelled","pipeline","createRenderPipeline","layout","vertex","module","createShaderModule","code","entryPoint","fragment","targets","format","primitive","topology","uniformBuffer","createBuffer","size","usage","GPUBufferUsage","UNIFORM","COPY_DST","bindGroup","createBindGroup","getBindGroupLayout","entries","binding","resource","buffer","uniformData","Float32Array","accumulatedTime","lastTimestamp","warned","bufferDestroyed","destroyBuffer","destroy","render","timestamp","props","getDirty","dt","currentSpeed","canvas","width","height","aspect","live","queue","writeBuffer","commandEncoder","createCommandEncoder","textureView","getCurrentTexture","createView","passEncoder","beginRenderPass","colorAttachments","view","clearValue","loadOp","storeOp","setPipeline","setBindGroup","draw","end","submit","finish","present","e","console","warn","requestAnimationFrame","of","ref","styles","onLayout","event","create","flex"],"sourceRoot":"../../../../src","sources":["components/ShaderView/index.tsx"],"mappings":"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","ignoreList":[]}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useCallback, useRef } from 'react';
|
|
4
|
+
import { StyleSheet, View } from 'react-native';
|
|
5
|
+
import { Gesture, GestureDetector } from 'react-native-gesture-handler';
|
|
6
|
+
import { createSynchronizable } from 'react-native-worklets';
|
|
7
|
+
import ShaderView from "../ShaderView/index.js";
|
|
8
|
+
import { useParamsSynchronizable } from "../../hooks/useParamsSynchronizable.js";
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* A {@link ShaderView} that feeds touch input into the shader's `u.live`:
|
|
12
|
+
*
|
|
13
|
+
* - `live.x` → pointer X, normalized 0..1 (left → right)
|
|
14
|
+
* - `live.y` → pointer Y, normalized 0..1 (bottom → top, matching UV space)
|
|
15
|
+
* - `live.z` → 1.0 while touching, 0.0 when released
|
|
16
|
+
* - `live.w` → 0.0 (reserved)
|
|
17
|
+
*
|
|
18
|
+
* Dragging moves the pointer **relatively** — it pushes from where the pointer
|
|
19
|
+
* already is rather than jumping under the finger — and a fling lets it glide to
|
|
20
|
+
* a stop. The position is **remembered**: it stays wherever it ended and is
|
|
21
|
+
* never reset; only the "touched" flag (`live.z`) toggles on release. A
|
|
22
|
+
* shader can read `live.xy` as a stable resting position and use `live.z`
|
|
23
|
+
* purely for touch-driven emphasis, so the effect never snaps back.
|
|
24
|
+
*
|
|
25
|
+
* The resting value before the first touch is `[0, 0, 0, 0]` by default; pass
|
|
26
|
+
* `initialParamsSynchronizable` to seed it — e.g. `[0.5, 0.5, 0, 0]` to start a
|
|
27
|
+
* pointer at screen center.
|
|
28
|
+
*
|
|
29
|
+
* The drag runs as a **worklet on the UI thread** and writes the synchronizable
|
|
30
|
+
* directly, so pointer updates never hop to the JS thread — matching the rest of
|
|
31
|
+
* the library, which renders off the JS thread. The render runtime reads the
|
|
32
|
+
* same synchronizable each frame.
|
|
33
|
+
*/
|
|
34
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
35
|
+
export default function ShaderViewWithPanGesture({
|
|
36
|
+
style,
|
|
37
|
+
initialParamsSynchronizable = [0, 0, 0, 0],
|
|
38
|
+
...props
|
|
39
|
+
}) {
|
|
40
|
+
const {
|
|
41
|
+
paramsSynchronizable
|
|
42
|
+
} = useParamsSynchronizable(initialParamsSynchronizable);
|
|
43
|
+
|
|
44
|
+
// View size, read inside the gesture worklets to normalize pointer coords.
|
|
45
|
+
const sizeRef = useRef(null);
|
|
46
|
+
if (sizeRef.current === null) {
|
|
47
|
+
sizeRef.current = createSynchronizable(Float64Array.of(1, 1));
|
|
48
|
+
}
|
|
49
|
+
const sizeSynchronizable = sizeRef.current;
|
|
50
|
+
|
|
51
|
+
// Generation of the current post-release glide; bumped to cancel an old one.
|
|
52
|
+
const momentumRef = useRef(null);
|
|
53
|
+
if (momentumRef.current === null) {
|
|
54
|
+
momentumRef.current = createSynchronizable(Float64Array.of(0));
|
|
55
|
+
}
|
|
56
|
+
const momentumSynchronizable = momentumRef.current;
|
|
57
|
+
|
|
58
|
+
// Pointer position when the current drag began — the pan moves the pointer
|
|
59
|
+
// relative to this, so a drag pushes from where it was rather than jumping.
|
|
60
|
+
const panStartRef = useRef(null);
|
|
61
|
+
if (panStartRef.current === null) {
|
|
62
|
+
panStartRef.current = createSynchronizable(Float64Array.of(0, 0));
|
|
63
|
+
}
|
|
64
|
+
const panStartSynchronizable = panStartRef.current;
|
|
65
|
+
const onLayout = useCallback(e => {
|
|
66
|
+
const {
|
|
67
|
+
width,
|
|
68
|
+
height
|
|
69
|
+
} = e.nativeEvent.layout;
|
|
70
|
+
sizeSynchronizable.setBlocking(() => Float64Array.of(width || 1, height || 1));
|
|
71
|
+
}, [sizeSynchronizable]);
|
|
72
|
+
|
|
73
|
+
// Worklet: runs on the UI thread and writes the normalized pointer straight
|
|
74
|
+
// into the synchronizable the render runtime reads, so a pointer move never
|
|
75
|
+
// touches the JS thread.
|
|
76
|
+
const writePointer = (nx, ny, active) => {
|
|
77
|
+
'worklet';
|
|
78
|
+
|
|
79
|
+
const x = Math.min(1, Math.max(0, nx));
|
|
80
|
+
const y = Math.min(1, Math.max(0, ny));
|
|
81
|
+
paramsSynchronizable.setBlocking(() => Float64Array.of(x, y, active, 0));
|
|
82
|
+
};
|
|
83
|
+
const stopMomentum = () => {
|
|
84
|
+
'worklet';
|
|
85
|
+
|
|
86
|
+
const next = (momentumSynchronizable.getDirty()[0] || 0) + 1;
|
|
87
|
+
momentumSynchronizable.setBlocking(() => Float64Array.of(next));
|
|
88
|
+
};
|
|
89
|
+
|
|
90
|
+
// Drop the touched flag in place — safety net for a gesture cancelled with no
|
|
91
|
+
// onEnd, so the flag never sticks.
|
|
92
|
+
const releaseFlag = () => {
|
|
93
|
+
'worklet';
|
|
94
|
+
|
|
95
|
+
const p = paramsSynchronizable.getDirty();
|
|
96
|
+
const x = p[0] || 0;
|
|
97
|
+
const y = p[1] || 0;
|
|
98
|
+
paramsSynchronizable.setBlocking(() => Float64Array.of(x, y, 0, 0));
|
|
99
|
+
};
|
|
100
|
+
|
|
101
|
+
// After release, drift from the last position along the fling velocity and
|
|
102
|
+
// decay to a stop — a little inertia. Runs on the UI thread via rAF, like the
|
|
103
|
+
// render loop, writing each frame into the same synchronizable.
|
|
104
|
+
const startMomentum = (velX, velY) => {
|
|
105
|
+
'worklet';
|
|
106
|
+
|
|
107
|
+
const s = sizeSynchronizable.getDirty();
|
|
108
|
+
const w = s[0] || 1;
|
|
109
|
+
const h = s[1] || 1;
|
|
110
|
+
|
|
111
|
+
// Flick speed in normalized units/sec, scaled to a subtle glide (Y flipped).
|
|
112
|
+
const SCALE = 0.12;
|
|
113
|
+
let vx = velX / w * SCALE;
|
|
114
|
+
let vy = -velY / h * SCALE;
|
|
115
|
+
const p = paramsSynchronizable.getDirty();
|
|
116
|
+
let x = p[0] || 0;
|
|
117
|
+
let y = p[1] || 0;
|
|
118
|
+
|
|
119
|
+
// Claim this glide; a newer one bumps the generation and this loop bails.
|
|
120
|
+
const gen = (momentumSynchronizable.getDirty()[0] || 0) + 1;
|
|
121
|
+
momentumSynchronizable.setBlocking(() => Float64Array.of(gen));
|
|
122
|
+
const FRICTION = 2; // 1/s — higher stops sooner
|
|
123
|
+
let last = -1;
|
|
124
|
+
|
|
125
|
+
// Plain closure (no 'worklet') so its accumulators and self-reference
|
|
126
|
+
// survive across frames; a serialized worklet would snapshot them by value.
|
|
127
|
+
const step = now => {
|
|
128
|
+
if ((momentumSynchronizable.getDirty()[0] || 0) !== gen) {
|
|
129
|
+
return;
|
|
130
|
+
}
|
|
131
|
+
const dt = last < 0 ? 0 : (now - last) / 1000;
|
|
132
|
+
last = now;
|
|
133
|
+
x = Math.min(1, Math.max(0, x + vx * dt));
|
|
134
|
+
y = Math.min(1, Math.max(0, y + vy * dt));
|
|
135
|
+
const decay = Math.exp(-FRICTION * dt);
|
|
136
|
+
vx = vx * decay;
|
|
137
|
+
vy = vy * decay;
|
|
138
|
+
paramsSynchronizable.setBlocking(() => Float64Array.of(x, y, 0, 0));
|
|
139
|
+
if (Math.abs(vx) + Math.abs(vy) > 0.0008) {
|
|
140
|
+
requestAnimationFrame(step);
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
requestAnimationFrame(step);
|
|
144
|
+
};
|
|
145
|
+
|
|
146
|
+
// Drag moves the pointer *relatively*: grab anywhere and push it from where it
|
|
147
|
+
// is, rather than snapping it under the finger. A plain tap leaves it put.
|
|
148
|
+
const pan = Gesture.Pan().onBegin(() => {
|
|
149
|
+
'worklet';
|
|
150
|
+
|
|
151
|
+
stopMomentum();
|
|
152
|
+
const p = paramsSynchronizable.getDirty();
|
|
153
|
+
const sx = p[0] || 0;
|
|
154
|
+
const sy = p[1] || 0;
|
|
155
|
+
panStartSynchronizable.setBlocking(() => Float64Array.of(sx, sy));
|
|
156
|
+
writePointer(sx, sy, 1);
|
|
157
|
+
}).onUpdate(e => {
|
|
158
|
+
'worklet';
|
|
159
|
+
|
|
160
|
+
const s = sizeSynchronizable.getDirty();
|
|
161
|
+
const w = s[0] || 1;
|
|
162
|
+
const h = s[1] || 1;
|
|
163
|
+
const start = panStartSynchronizable.getDirty();
|
|
164
|
+
// Add the drag delta; Y is flipped to match the shader's UV space.
|
|
165
|
+
writePointer((start[0] || 0) + e.translationX / w, (start[1] || 0) - e.translationY / h, 1);
|
|
166
|
+
}).onEnd(e => {
|
|
167
|
+
'worklet';
|
|
168
|
+
|
|
169
|
+
const p = paramsSynchronizable.getDirty();
|
|
170
|
+
writePointer(p[0] || 0, p[1] || 0, 0);
|
|
171
|
+
startMomentum(e.velocityX, e.velocityY);
|
|
172
|
+
}).onFinalize(() => {
|
|
173
|
+
'worklet';
|
|
174
|
+
|
|
175
|
+
releaseFlag();
|
|
176
|
+
});
|
|
177
|
+
return /*#__PURE__*/_jsx(GestureDetector, {
|
|
178
|
+
gesture: pan,
|
|
179
|
+
children: /*#__PURE__*/_jsx(View, {
|
|
180
|
+
style: [styles.fill, style],
|
|
181
|
+
onLayout: onLayout,
|
|
182
|
+
collapsable: false,
|
|
183
|
+
children: /*#__PURE__*/_jsx(ShaderView, {
|
|
184
|
+
...props,
|
|
185
|
+
paramsSynchronizable: paramsSynchronizable,
|
|
186
|
+
style: StyleSheet.absoluteFill
|
|
187
|
+
})
|
|
188
|
+
})
|
|
189
|
+
});
|
|
190
|
+
}
|
|
191
|
+
const styles = StyleSheet.create({
|
|
192
|
+
fill: {
|
|
193
|
+
flex: 1
|
|
194
|
+
}
|
|
195
|
+
});
|
|
196
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useCallback","useRef","StyleSheet","View","Gesture","GestureDetector","createSynchronizable","ShaderView","useParamsSynchronizable","jsx","_jsx","ShaderViewWithPanGesture","style","initialParamsSynchronizable","props","paramsSynchronizable","sizeRef","current","Float64Array","of","sizeSynchronizable","momentumRef","momentumSynchronizable","panStartRef","panStartSynchronizable","onLayout","e","width","height","nativeEvent","layout","setBlocking","writePointer","nx","ny","active","x","Math","min","max","y","stopMomentum","next","getDirty","releaseFlag","p","startMomentum","velX","velY","s","w","h","SCALE","vx","vy","gen","FRICTION","last","step","now","dt","decay","exp","abs","requestAnimationFrame","pan","Pan","onBegin","sx","sy","onUpdate","start","translationX","translationY","onEnd","velocityX","velocityY","onFinalize","gesture","children","styles","fill","collapsable","absoluteFill","create","flex"],"sourceRoot":"../../../../src","sources":["components/ShaderViewWithPanGesture/index.tsx"],"mappings":"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","ignoreList":[]}
|