react-native-effects 0.0.1 → 0.2.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/LICENSE +20 -0
- package/README.md +313 -0
- package/lib/module/components/Aurora.js +184 -0
- package/lib/module/components/Aurora.js.map +1 -0
- package/lib/module/components/CalicoSwirl.js +155 -0
- package/lib/module/components/CalicoSwirl.js.map +1 -0
- package/lib/module/components/Campfire.js +225 -0
- package/lib/module/components/Campfire.js.map +1 -0
- package/lib/module/components/CircularGradient.js +52 -0
- package/lib/module/components/CircularGradient.js.map +1 -0
- package/lib/module/components/Iridescence.js +57 -0
- package/lib/module/components/Iridescence.js.map +1 -0
- package/lib/module/components/LinearGradient.js +48 -0
- package/lib/module/components/LinearGradient.js.map +1 -0
- package/lib/module/components/LiquidChrome.js +75 -0
- package/lib/module/components/LiquidChrome.js.map +1 -0
- package/lib/module/components/ShaderView/index.js +252 -0
- package/lib/module/components/ShaderView/index.js.map +1 -0
- package/lib/module/components/ShaderView/types.js +4 -0
- package/lib/module/components/ShaderView/types.js.map +1 -0
- package/lib/module/components/ShaderViewWithPanGesture/index.js +196 -0
- package/lib/module/components/ShaderViewWithPanGesture/index.js.map +1 -0
- package/lib/module/components/Silk.js +83 -0
- package/lib/module/components/Silk.js.map +1 -0
- package/lib/module/consts.js +154 -0
- package/lib/module/consts.js.map +1 -0
- package/lib/module/hooks/useClock.js +15 -0
- package/lib/module/hooks/useClock.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 +54 -0
- package/lib/module/hooks/useWGPUSetup.js.map +1 -0
- package/lib/module/index.js +15 -0
- package/lib/module/index.js.map +1 -0
- package/lib/module/package.json +1 -0
- package/lib/module/shaders/TRIANGLE_VERTEX_SHADER.js +20 -0
- package/lib/module/shaders/TRIANGLE_VERTEX_SHADER.js.map +1 -0
- package/lib/module/shaders/uniforms.js +21 -0
- package/lib/module/shaders/uniforms.js.map +1 -0
- package/lib/module/utils/backgroundRuntime.js +12 -0
- package/lib/module/utils/backgroundRuntime.js.map +1 -0
- package/lib/module/utils/colors.js +94 -0
- package/lib/module/utils/colors.js.map +1 -0
- package/lib/module/utils/initWebGPU.js +40 -0
- package/lib/module/utils/initWebGPU.js.map +1 -0
- package/lib/typescript/package.json +1 -0
- package/lib/typescript/src/components/Aurora.d.ts +17 -0
- package/lib/typescript/src/components/Aurora.d.ts.map +1 -0
- package/lib/typescript/src/components/CalicoSwirl.d.ts +13 -0
- package/lib/typescript/src/components/CalicoSwirl.d.ts.map +1 -0
- package/lib/typescript/src/components/Campfire.d.ts +17 -0
- package/lib/typescript/src/components/Campfire.d.ts.map +1 -0
- package/lib/typescript/src/components/CircularGradient.d.ts +19 -0
- package/lib/typescript/src/components/CircularGradient.d.ts.map +1 -0
- package/lib/typescript/src/components/Iridescence.d.ts +11 -0
- package/lib/typescript/src/components/Iridescence.d.ts.map +1 -0
- package/lib/typescript/src/components/LinearGradient.d.ts +15 -0
- package/lib/typescript/src/components/LinearGradient.d.ts.map +1 -0
- package/lib/typescript/src/components/LiquidChrome.d.ts +17 -0
- package/lib/typescript/src/components/LiquidChrome.d.ts.map +1 -0
- package/lib/typescript/src/components/ShaderView/index.d.ts +3 -0
- package/lib/typescript/src/components/ShaderView/index.d.ts.map +1 -0
- package/lib/typescript/src/components/ShaderView/types.d.ts +35 -0
- package/lib/typescript/src/components/ShaderView/types.d.ts.map +1 -0
- 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 +17 -0
- package/lib/typescript/src/components/Silk.d.ts.map +1 -0
- package/lib/typescript/src/consts.d.ts +2 -0
- package/lib/typescript/src/consts.d.ts.map +1 -0
- package/lib/typescript/src/hooks/useClock.d.ts +3 -0
- package/lib/typescript/src/hooks/useClock.d.ts.map +1 -0
- 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 +15 -0
- package/lib/typescript/src/hooks/useWGPUSetup.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +16 -0
- package/lib/typescript/src/index.d.ts.map +1 -0
- package/lib/typescript/src/shaders/TRIANGLE_VERTEX_SHADER.d.ts +2 -0
- package/lib/typescript/src/shaders/TRIANGLE_VERTEX_SHADER.d.ts.map +1 -0
- package/lib/typescript/src/shaders/uniforms.d.ts +6 -0
- package/lib/typescript/src/shaders/uniforms.d.ts.map +1 -0
- package/lib/typescript/src/utils/backgroundRuntime.d.ts +3 -0
- package/lib/typescript/src/utils/backgroundRuntime.d.ts.map +1 -0
- package/lib/typescript/src/utils/colors.d.ts +22 -0
- package/lib/typescript/src/utils/colors.d.ts.map +1 -0
- package/lib/typescript/src/utils/initWebGPU.d.ts +23 -0
- package/lib/typescript/src/utils/initWebGPU.d.ts.map +1 -0
- package/package.json +175 -7
- package/src/components/Aurora.tsx +203 -0
- package/src/components/CalicoSwirl.tsx +167 -0
- package/src/components/Campfire.tsx +244 -0
- package/src/components/CircularGradient.tsx +76 -0
- package/src/components/Iridescence.tsx +67 -0
- package/src/components/LinearGradient.tsx +62 -0
- package/src/components/LiquidChrome.tsx +94 -0
- package/src/components/ShaderView/index.tsx +262 -0
- package/src/components/ShaderView/types.ts +36 -0
- package/src/components/ShaderViewWithPanGesture/index.tsx +225 -0
- package/src/components/Silk.tsx +102 -0
- package/src/consts.ts +152 -0
- package/src/hooks/useClock.ts +20 -0
- package/src/hooks/useParamsSynchronizable.ts +52 -0
- package/src/hooks/useWGPUSetup.tsx +73 -0
- package/src/index.tsx +32 -0
- package/src/shaders/TRIANGLE_VERTEX_SHADER.ts +17 -0
- package/src/shaders/uniforms.ts +18 -0
- package/src/utils/backgroundRuntime.ts +10 -0
- package/src/utils/colors.ts +117 -0
- package/src/utils/initWebGPU.ts +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Blazej Kustra
|
|
4
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
5
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
6
|
+
in the Software without restriction, including without limitation the rights
|
|
7
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
8
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
9
|
+
furnished to do so, subject to the following conditions:
|
|
10
|
+
|
|
11
|
+
The above copyright notice and this permission notice shall be included in all
|
|
12
|
+
copies or substantial portions of the Software.
|
|
13
|
+
|
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
15
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
16
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
17
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
18
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
19
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
20
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
# react-native-effects
|
|
2
|
+
|
|
3
|
+
https://github.com/user-attachments/assets/5141208a-655a-4de8-94fb-3e66351bf36f
|
|
4
|
+
|
|
5
|
+
> **Experimental** — APIs may change without notice. Relies on `react-native-worklets` bundle mode, which is not enabled by default yet.
|
|
6
|
+
|
|
7
|
+
WebGPU-powered effects running on **background thread** in React Native.
|
|
8
|
+
|
|
9
|
+
## Features
|
|
10
|
+
|
|
11
|
+
- **WebGPU rendering** via `react-native-webgpu`
|
|
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
|
+
- **Drop-in components** — use like any React Native `View`
|
|
14
|
+
- **Customizable** — control colors, speed, intensity, and effect-specific parameters
|
|
15
|
+
- **Animated & static** modes for gradients
|
|
16
|
+
- **Build your own** — create custom effects with `ShaderView` and WGSL shaders
|
|
17
|
+
|
|
18
|
+
## Components
|
|
19
|
+
|
|
20
|
+
| Component | Description |
|
|
21
|
+
| ------------------ | ---------------------------------------------- |
|
|
22
|
+
| `Iridescence` | Mesmerizing iridescent animated effect |
|
|
23
|
+
| `LiquidChrome` | Fluid metallic surface |
|
|
24
|
+
| `Silk` | Smooth flowing silk fabric |
|
|
25
|
+
| `Campfire` | Fire with drifting sparks and smoke |
|
|
26
|
+
| `CalicoSwirl` | Warped noise pattern with flowing colors |
|
|
27
|
+
| `Aurora` | Northern lights with flowing curtains of light |
|
|
28
|
+
| `LinearGradient` | Smooth linear gradients (static & animated) |
|
|
29
|
+
| `CircularGradient` | Customizable circular/radial gradients |
|
|
30
|
+
|
|
31
|
+
## ShaderView
|
|
32
|
+
|
|
33
|
+
`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.
|
|
34
|
+
|
|
35
|
+
```tsx
|
|
36
|
+
import { ShaderView } from 'react-native-effects';
|
|
37
|
+
|
|
38
|
+
<ShaderView
|
|
39
|
+
fragmentShader={myShader}
|
|
40
|
+
colors={['#ff0000', '#0000ff']}
|
|
41
|
+
params={[1.0, 0.5]}
|
|
42
|
+
speed={1.0}
|
|
43
|
+
style={{ width: '100%', height: 300 }}
|
|
44
|
+
/>;
|
|
45
|
+
```
|
|
46
|
+
|
|
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 |
|
|
56
|
+
|
|
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.
|
|
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
|
+
|
|
96
|
+
## Installation
|
|
97
|
+
|
|
98
|
+
```sh
|
|
99
|
+
npm install react-native-effects
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### Peer dependencies
|
|
103
|
+
|
|
104
|
+
```sh
|
|
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
|
+
}
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
In a bare React Native project, set `minSdkVersion = 26` in `android/build.gradle`.
|
|
123
|
+
|
|
124
|
+
### Bundle mode setup
|
|
125
|
+
|
|
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.
|
|
127
|
+
|
|
128
|
+
**package.json** (add at root level)
|
|
129
|
+
|
|
130
|
+
```json
|
|
131
|
+
{
|
|
132
|
+
"worklets": {
|
|
133
|
+
"staticFeatureFlags": {
|
|
134
|
+
"BUNDLE_MODE_ENABLED": true,
|
|
135
|
+
"FETCH_PREVIEW_ENABLED": true
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
```
|
|
140
|
+
|
|
141
|
+
<details>
|
|
142
|
+
<summary><strong>Bare React Native</strong></summary>
|
|
143
|
+
|
|
144
|
+
**babel.config.js**
|
|
145
|
+
|
|
146
|
+
```js
|
|
147
|
+
module.exports = {
|
|
148
|
+
presets: ['module:@react-native/babel-preset'],
|
|
149
|
+
plugins: [
|
|
150
|
+
['react-native-worklets/plugin', { bundleMode: true, strictGlobal: true }],
|
|
151
|
+
],
|
|
152
|
+
};
|
|
153
|
+
```
|
|
154
|
+
|
|
155
|
+
**metro.config.js**
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
const { getDefaultConfig, mergeConfig } = require('@react-native/metro-config');
|
|
159
|
+
const {
|
|
160
|
+
getBundleModeMetroConfig,
|
|
161
|
+
} = require('react-native-worklets/bundleMode');
|
|
162
|
+
|
|
163
|
+
let config = getDefaultConfig(__dirname);
|
|
164
|
+
config = getBundleModeMetroConfig(config);
|
|
165
|
+
|
|
166
|
+
// CRITICAL: Enable inlineRequires for worklets compatibility
|
|
167
|
+
config.transformer = {
|
|
168
|
+
...config.transformer,
|
|
169
|
+
getTransformOptions: async () => ({
|
|
170
|
+
transform: {
|
|
171
|
+
inlineRequires: true,
|
|
172
|
+
},
|
|
173
|
+
}),
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
module.exports = config;
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
</details>
|
|
180
|
+
|
|
181
|
+
<details>
|
|
182
|
+
<summary><strong>Expo</strong></summary>
|
|
183
|
+
|
|
184
|
+
Install additional dev dependencies:
|
|
185
|
+
|
|
186
|
+
```sh
|
|
187
|
+
npm install -D babel-preset-expo @react-native/metro-config
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
**babel.config.js**
|
|
191
|
+
|
|
192
|
+
```js
|
|
193
|
+
module.exports = function (api) {
|
|
194
|
+
api.cache(true);
|
|
195
|
+
return {
|
|
196
|
+
presets: ['babel-preset-expo'],
|
|
197
|
+
plugins: [
|
|
198
|
+
[
|
|
199
|
+
'react-native-worklets/plugin',
|
|
200
|
+
{ bundleMode: true, strictGlobal: true },
|
|
201
|
+
],
|
|
202
|
+
],
|
|
203
|
+
};
|
|
204
|
+
};
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
**metro.config.js**
|
|
208
|
+
|
|
209
|
+
```js
|
|
210
|
+
const { getDefaultConfig } = require('expo/metro-config');
|
|
211
|
+
const {
|
|
212
|
+
getBundleModeMetroConfig,
|
|
213
|
+
} = require('react-native-worklets/bundleMode');
|
|
214
|
+
|
|
215
|
+
/** @type {import('expo/metro-config').MetroConfig} */
|
|
216
|
+
let config = getDefaultConfig(__dirname);
|
|
217
|
+
config = getBundleModeMetroConfig(config);
|
|
218
|
+
|
|
219
|
+
// CRITICAL: Enable inlineRequires for worklets compatibility in Expo
|
|
220
|
+
config.transformer = {
|
|
221
|
+
...config.transformer,
|
|
222
|
+
getTransformOptions: async () => ({
|
|
223
|
+
transform: {
|
|
224
|
+
inlineRequires: true,
|
|
225
|
+
},
|
|
226
|
+
}),
|
|
227
|
+
};
|
|
228
|
+
|
|
229
|
+
module.exports = config;
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
</details>
|
|
233
|
+
|
|
234
|
+
## Usage
|
|
235
|
+
|
|
236
|
+
```tsx
|
|
237
|
+
import { Iridescence, LiquidChrome, Aurora } from 'react-native-effects';
|
|
238
|
+
|
|
239
|
+
// Full-screen animated background
|
|
240
|
+
<Iridescence style={StyleSheet.absoluteFillObject} />
|
|
241
|
+
|
|
242
|
+
// Metallic effect with custom speed
|
|
243
|
+
<LiquidChrome style={{ width: '100%', height: 300 }} speed={1.5} />
|
|
244
|
+
|
|
245
|
+
// Aurora borealis with custom parameters
|
|
246
|
+
<Aurora
|
|
247
|
+
style={StyleSheet.absoluteFillObject}
|
|
248
|
+
color="#4ade80"
|
|
249
|
+
speed={1.0}
|
|
250
|
+
intensity={1.0}
|
|
251
|
+
layers={3}
|
|
252
|
+
waviness={1.0}
|
|
253
|
+
/>
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### Common Props
|
|
257
|
+
|
|
258
|
+
All shader components accept standard `View` props plus:
|
|
259
|
+
|
|
260
|
+
| Prop | Type | Default | Description |
|
|
261
|
+
| ------- | ------------------ | ------- | -------------------------- |
|
|
262
|
+
| `color` | `string \| number` | varies | Base tint color |
|
|
263
|
+
| `speed` | `number` | `1.0` | Animation speed multiplier |
|
|
264
|
+
|
|
265
|
+
### Aurora
|
|
266
|
+
|
|
267
|
+
| Prop | Type | Default | Description |
|
|
268
|
+
| ----------- | -------- | ------- | ------------------------------ |
|
|
269
|
+
| `intensity` | `number` | `1.0` | Brightness of the aurora bands |
|
|
270
|
+
| `layers` | `number` | `3` | Number of curtain layers (1-5) |
|
|
271
|
+
| `waviness` | `number` | `1.0` | Turbulence of the curtains |
|
|
272
|
+
|
|
273
|
+
### Gradients
|
|
274
|
+
|
|
275
|
+
```tsx
|
|
276
|
+
import { LinearGradient, CircularGradient } from 'react-native-effects';
|
|
277
|
+
|
|
278
|
+
<LinearGradient
|
|
279
|
+
style={{ width: '100%', height: 200 }}
|
|
280
|
+
colors={['#ff0000', '#0000ff']}
|
|
281
|
+
angle={45}
|
|
282
|
+
/>
|
|
283
|
+
|
|
284
|
+
<CircularGradient
|
|
285
|
+
style={{ width: 200, height: 200 }}
|
|
286
|
+
colors={['#ff0000', '#0000ff']}
|
|
287
|
+
/>
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
## Create Your Own Effect
|
|
291
|
+
|
|
292
|
+
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.
|
|
293
|
+
|
|
294
|
+
## Running the example app
|
|
295
|
+
|
|
296
|
+
```sh
|
|
297
|
+
yarn install
|
|
298
|
+
yarn prebuild # generates native iOS/Android projects
|
|
299
|
+
yarn ios # run on iOS simulator
|
|
300
|
+
yarn android # run on Android emulator
|
|
301
|
+
```
|
|
302
|
+
|
|
303
|
+
To start fresh after config changes, use `yarn prebuild:clean` instead of `yarn prebuild`.
|
|
304
|
+
|
|
305
|
+
## Contributing
|
|
306
|
+
|
|
307
|
+
- [Development workflow](CONTRIBUTING.md#development-workflow)
|
|
308
|
+
- [Sending a pull request](CONTRIBUTING.md#sending-a-pull-request)
|
|
309
|
+
- [Code of conduct](CODE_OF_CONDUCT.md)
|
|
310
|
+
|
|
311
|
+
## License
|
|
312
|
+
|
|
313
|
+
MIT
|
|
@@ -0,0 +1,184 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import ShaderView from "./ShaderView/index.js";
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
export default function Aurora({
|
|
7
|
+
color = '#4ade80',
|
|
8
|
+
speed = 1.0,
|
|
9
|
+
intensity = 1.0,
|
|
10
|
+
layers = 3.0,
|
|
11
|
+
waviness = 1.0,
|
|
12
|
+
...viewProps
|
|
13
|
+
}) {
|
|
14
|
+
const colors = useMemo(() => [color], [color]);
|
|
15
|
+
const params = useMemo(() => [intensity, layers, waviness], [intensity, layers, waviness]);
|
|
16
|
+
return /*#__PURE__*/_jsx(ShaderView, {
|
|
17
|
+
fragmentShader: AURORA_SHADER,
|
|
18
|
+
colors: colors,
|
|
19
|
+
params: params,
|
|
20
|
+
speed: speed,
|
|
21
|
+
isStatic: false,
|
|
22
|
+
...viewProps
|
|
23
|
+
});
|
|
24
|
+
}
|
|
25
|
+
const AURORA_SHADER = /* wgsl */`
|
|
26
|
+
struct Uniforms {
|
|
27
|
+
resolution: vec4<f32>,
|
|
28
|
+
time: vec4<f32>,
|
|
29
|
+
color0: vec4<f32>,
|
|
30
|
+
color1: vec4<f32>,
|
|
31
|
+
params0: vec4<f32>,
|
|
32
|
+
params1: vec4<f32>,
|
|
33
|
+
};
|
|
34
|
+
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
35
|
+
|
|
36
|
+
// Hash function for pseudo-random values
|
|
37
|
+
fn hash(p: vec2<f32>) -> f32 {
|
|
38
|
+
var p3 = fract(vec3<f32>(p.x, p.y, p.x) * 0.13);
|
|
39
|
+
p3 += dot(p3, vec3<f32>(p3.y + 3.333, p3.z + 3.333, p3.x + 3.333));
|
|
40
|
+
return fract((p3.x + p3.y) * p3.z);
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
// 2D noise
|
|
44
|
+
fn noise(p: vec2<f32>) -> f32 {
|
|
45
|
+
let i = floor(p);
|
|
46
|
+
let f = fract(p);
|
|
47
|
+
let u_s = f * f * (3.0 - 2.0 * f);
|
|
48
|
+
|
|
49
|
+
let a = hash(i);
|
|
50
|
+
let b = hash(i + vec2<f32>(1.0, 0.0));
|
|
51
|
+
let c = hash(i + vec2<f32>(0.0, 1.0));
|
|
52
|
+
let d = hash(i + vec2<f32>(1.0, 1.0));
|
|
53
|
+
|
|
54
|
+
return mix(mix(a, b, u_s.x), mix(c, d, u_s.x), u_s.y);
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
// Fractional Brownian Motion
|
|
58
|
+
fn fbm(p_in: vec2<f32>, octaves: i32) -> f32 {
|
|
59
|
+
var p = p_in;
|
|
60
|
+
var value = 0.0;
|
|
61
|
+
var amplitude = 0.5;
|
|
62
|
+
var frequency = 1.0;
|
|
63
|
+
|
|
64
|
+
for (var i = 0; i < octaves; i++) {
|
|
65
|
+
value += amplitude * noise(p * frequency);
|
|
66
|
+
p = p * 2.01 + vec2<f32>(1.7, 9.2);
|
|
67
|
+
amplitude *= 0.5;
|
|
68
|
+
frequency *= 1.0;
|
|
69
|
+
}
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
// Single aurora curtain layer
|
|
74
|
+
fn auroraLayer(uv: vec2<f32>, time: f32, offset: f32, waviness: f32) -> f32 {
|
|
75
|
+
// Horizontal position with time-based drift
|
|
76
|
+
let drift = time * 0.15 + offset * 2.5;
|
|
77
|
+
|
|
78
|
+
// Create the curtain shape using sine waves
|
|
79
|
+
let wave1 = sin(uv.x * 2.0 * waviness + drift + offset * 6.0) * 0.3;
|
|
80
|
+
let wave2 = sin(uv.x * 3.5 * waviness + drift * 1.3 + offset * 4.0) * 0.15;
|
|
81
|
+
let wave3 = sin(uv.x * 7.0 * waviness + drift * 0.7 + offset * 8.0) * 0.08;
|
|
82
|
+
|
|
83
|
+
// FBM noise for organic turbulence
|
|
84
|
+
let noiseVal = fbm(vec2<f32>(uv.x * 1.5 * waviness + drift * 0.5, uv.y * 0.8 + offset * 3.0), 4);
|
|
85
|
+
|
|
86
|
+
// Curtain center position (wavy vertical line)
|
|
87
|
+
let curtainCenter = 0.5 + wave1 + wave2 + wave3 + (noiseVal - 0.5) * 0.25 * waviness;
|
|
88
|
+
|
|
89
|
+
// Distance from curtain center for glow
|
|
90
|
+
let dist = abs(uv.y - curtainCenter);
|
|
91
|
+
|
|
92
|
+
// Soft glow falloff
|
|
93
|
+
let glow = exp(-dist * dist * 15.0) * 0.8;
|
|
94
|
+
|
|
95
|
+
// Add shimmer using noise
|
|
96
|
+
let shimmer = fbm(vec2<f32>(uv.x * 4.0 + time * 0.3, uv.y * 8.0 + offset * 5.0), 3);
|
|
97
|
+
let shimmerEffect = glow * (0.7 + 0.3 * shimmer);
|
|
98
|
+
|
|
99
|
+
// Fade toward bottom of screen (aurora appears in upper portion)
|
|
100
|
+
let heightFade = smoothstep(0.0, 0.6, uv.y);
|
|
101
|
+
|
|
102
|
+
return shimmerEffect * heightFade;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Stars in the background
|
|
106
|
+
fn stars(uv: vec2<f32>, time: f32) -> f32 {
|
|
107
|
+
let grid = floor(uv * 50.0);
|
|
108
|
+
let h = hash(grid);
|
|
109
|
+
|
|
110
|
+
// Only show some cells as stars
|
|
111
|
+
let star = step(0.92, h);
|
|
112
|
+
|
|
113
|
+
// Twinkle effect
|
|
114
|
+
let twinkle = 0.5 + 0.5 * sin(time * (1.0 + h * 3.0) + h * 6.28);
|
|
115
|
+
|
|
116
|
+
let cellUv = fract(uv * 50.0) - 0.5;
|
|
117
|
+
let d = length(cellUv);
|
|
118
|
+
let point = exp(-d * d * 80.0);
|
|
119
|
+
|
|
120
|
+
return point * star * twinkle * 0.6;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
@fragment
|
|
124
|
+
fn main(@location(0) ndc: vec2<f32>) -> @location(0) vec4<f32> {
|
|
125
|
+
let time = u.time.x;
|
|
126
|
+
let intensity = u.params0.x;
|
|
127
|
+
let layerCount = u.params0.y;
|
|
128
|
+
let waviness = u.params0.z;
|
|
129
|
+
|
|
130
|
+
// Map NDC (-1..1) to UV (0..1)
|
|
131
|
+
let uv = ndc * 0.5 + 0.5;
|
|
132
|
+
|
|
133
|
+
// Dark sky background
|
|
134
|
+
let skyTop = vec3<f32>(0.0, 0.0, 0.02);
|
|
135
|
+
let skyBottom = vec3<f32>(0.01, 0.01, 0.04);
|
|
136
|
+
var col = mix(skyBottom, skyTop, uv.y);
|
|
137
|
+
|
|
138
|
+
// Add stars
|
|
139
|
+
let starVal = stars(uv, time);
|
|
140
|
+
// Dim stars where aurora is bright (computed later)
|
|
141
|
+
var auroraTotal = 0.0;
|
|
142
|
+
|
|
143
|
+
// Aurora color palette
|
|
144
|
+
let green = vec3<f32>(0.2, 0.9, 0.4);
|
|
145
|
+
let cyan = vec3<f32>(0.1, 0.7, 0.8);
|
|
146
|
+
let purple = vec3<f32>(0.5, 0.2, 0.8);
|
|
147
|
+
let pink = vec3<f32>(0.7, 0.2, 0.5);
|
|
148
|
+
|
|
149
|
+
// Accumulate aurora layers
|
|
150
|
+
let numLayers = i32(clamp(layerCount, 1.0, 5.0));
|
|
151
|
+
|
|
152
|
+
for (var i = 0; i < 5; i++) {
|
|
153
|
+
if (i >= numLayers) { break; }
|
|
154
|
+
|
|
155
|
+
let fi = f32(i);
|
|
156
|
+
let layerOffset = fi * 0.7;
|
|
157
|
+
|
|
158
|
+
let layer = auroraLayer(uv, time, layerOffset, waviness);
|
|
159
|
+
|
|
160
|
+
// Color varies per layer and position
|
|
161
|
+
let colorPhase = fi / f32(numLayers) + uv.x * 0.3 + time * 0.02;
|
|
162
|
+
let c1 = mix(green, cyan, sin(colorPhase * 3.14) * 0.5 + 0.5);
|
|
163
|
+
let c2 = mix(purple, pink, cos(colorPhase * 2.5) * 0.5 + 0.5);
|
|
164
|
+
let layerColor = mix(c1, c2, sin(colorPhase * 2.0 + fi) * 0.5 + 0.5);
|
|
165
|
+
|
|
166
|
+
col += layerColor * layer * intensity * (1.0 / f32(numLayers)) * 2.5;
|
|
167
|
+
auroraTotal += layer;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Add stars (dimmed where aurora is bright)
|
|
171
|
+
let starDim = max(0.0, 1.0 - auroraTotal * 2.0);
|
|
172
|
+
col += vec3<f32>(starVal * starDim);
|
|
173
|
+
|
|
174
|
+
// Apply tint color
|
|
175
|
+
col *= u.color0.rgb;
|
|
176
|
+
|
|
177
|
+
// Tone mapping - prevent over-saturation
|
|
178
|
+
col = col / (col + vec3<f32>(1.0));
|
|
179
|
+
col = pow(col, vec3<f32>(0.9));
|
|
180
|
+
|
|
181
|
+
return vec4<f32>(col, u.color0.a);
|
|
182
|
+
}
|
|
183
|
+
`;
|
|
184
|
+
//# sourceMappingURL=Aurora.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useMemo","ShaderView","jsx","_jsx","Aurora","color","speed","intensity","layers","waviness","viewProps","colors","params","fragmentShader","AURORA_SHADER","isStatic"],"sourceRoot":"../../../src","sources":["components/Aurora.tsx"],"mappings":";;AAAA,SAASA,OAAO,QAAQ,OAAO;AAG/B,OAAOC,UAAU,MAAM,uBAAc;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAetC,eAAe,SAASC,MAAMA,CAAC;EAC7BC,KAAK,GAAG,SAAS;EACjBC,KAAK,GAAG,GAAG;EACXC,SAAS,GAAG,GAAG;EACfC,MAAM,GAAG,GAAG;EACZC,QAAQ,GAAG,GAAG;EACd,GAAGC;AACE,CAAC,EAAE;EACR,MAAMC,MAAM,GAAGX,OAAO,CAAC,MAAM,CAACK,KAAK,CAAC,EAAE,CAACA,KAAK,CAAC,CAAC;EAC9C,MAAMO,MAAM,GAAGZ,OAAO,CACpB,MAAM,CAACO,SAAS,EAAEC,MAAM,EAAEC,QAAQ,CAAC,EACnC,CAACF,SAAS,EAAEC,MAAM,EAAEC,QAAQ,CAC9B,CAAC;EAED,oBACEN,IAAA,CAACF,UAAU;IACTY,cAAc,EAAEC,aAAc;IAC9BH,MAAM,EAAEA,MAAO;IACfC,MAAM,EAAEA,MAAO;IACfN,KAAK,EAAEA,KAAM;IACbS,QAAQ,EAAE,KAAM;IAAA,GACZL;EAAS,CACd,CAAC;AAEN;AAEA,MAAMI,aAAa,GAAG,UAAW;AACjC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC","ignoreList":[]}
|
|
@@ -0,0 +1,155 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
|
|
3
|
+
import { useMemo } from 'react';
|
|
4
|
+
import ShaderView from "./ShaderView/index.js";
|
|
5
|
+
import { jsx as _jsx } from "react/jsx-runtime";
|
|
6
|
+
export default function CalicoSwirl({
|
|
7
|
+
color = '#ffffff',
|
|
8
|
+
speed = 1.0,
|
|
9
|
+
intensity = 1.0,
|
|
10
|
+
...viewProps
|
|
11
|
+
}) {
|
|
12
|
+
const colors = useMemo(() => [color], [color]);
|
|
13
|
+
const params = useMemo(() => [intensity], [intensity]);
|
|
14
|
+
return /*#__PURE__*/_jsx(ShaderView, {
|
|
15
|
+
fragmentShader: CALICO_SWIRL_SHADER,
|
|
16
|
+
colors: colors,
|
|
17
|
+
params: params,
|
|
18
|
+
speed: speed,
|
|
19
|
+
isStatic: false,
|
|
20
|
+
...viewProps
|
|
21
|
+
});
|
|
22
|
+
}
|
|
23
|
+
const CALICO_SWIRL_SHADER = /* wgsl */`
|
|
24
|
+
struct Uniforms {
|
|
25
|
+
resolution: vec4<f32>,
|
|
26
|
+
time: vec4<f32>,
|
|
27
|
+
color0: vec4<f32>,
|
|
28
|
+
color1: vec4<f32>,
|
|
29
|
+
params0: vec4<f32>,
|
|
30
|
+
params1: vec4<f32>,
|
|
31
|
+
};
|
|
32
|
+
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
33
|
+
|
|
34
|
+
const m = mat2x2<f32>(0.80, 0.60, -0.60, 0.80);
|
|
35
|
+
|
|
36
|
+
fn noise(p: vec2<f32>) -> f32 {
|
|
37
|
+
return sin(p.x) * sin(p.y);
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
fn fbm4(p_in: vec2<f32>) -> f32 {
|
|
41
|
+
var p = p_in;
|
|
42
|
+
var f = 0.0;
|
|
43
|
+
f += 0.5000 * noise(p);
|
|
44
|
+
p = m * p * 2.02;
|
|
45
|
+
f += 0.2500 * noise(p);
|
|
46
|
+
p = m * p * 2.03;
|
|
47
|
+
f += 0.1250 * noise(p);
|
|
48
|
+
p = m * p * 2.01;
|
|
49
|
+
f += 0.0625 * noise(p);
|
|
50
|
+
return f / 0.9375;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fn fbm6(p_in: vec2<f32>) -> f32 {
|
|
54
|
+
var p = p_in;
|
|
55
|
+
var f = 0.0;
|
|
56
|
+
f += 0.500000 * (0.5 + 0.5 * noise(p));
|
|
57
|
+
p = m * p * 2.02;
|
|
58
|
+
f += 0.250000 * (0.5 + 0.5 * noise(p));
|
|
59
|
+
p = m * p * 2.03;
|
|
60
|
+
f += 0.125000 * (0.5 + 0.5 * noise(p));
|
|
61
|
+
p = m * p * 2.01;
|
|
62
|
+
f += 0.062500 * (0.5 + 0.5 * noise(p));
|
|
63
|
+
p = m * p * 2.04;
|
|
64
|
+
f += 0.031250 * (0.5 + 0.5 * noise(p));
|
|
65
|
+
p = m * p * 2.01;
|
|
66
|
+
f += 0.015625 * (0.5 + 0.5 * noise(p));
|
|
67
|
+
return f / 0.96875;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
fn fbm4_2(p: vec2<f32>) -> vec2<f32> {
|
|
71
|
+
return vec2<f32>(fbm4(p), fbm4(p + vec2<f32>(7.8)));
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
fn fbm6_2(p: vec2<f32>) -> vec2<f32> {
|
|
75
|
+
return vec2<f32>(fbm6(p + vec2<f32>(16.8)), fbm6(p + vec2<f32>(11.5)));
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
fn func(q: vec2<f32>, time: f32) -> vec4<f32> {
|
|
79
|
+
var q_mod = q;
|
|
80
|
+
q_mod += 0.03 * sin(vec2<f32>(0.27, 0.23) * time + length(q) * vec2<f32>(4.1, 4.3));
|
|
81
|
+
|
|
82
|
+
let o = fbm4_2(0.9 * q_mod);
|
|
83
|
+
|
|
84
|
+
var o_mod = o;
|
|
85
|
+
o_mod += 0.04 * sin(vec2<f32>(0.12, 0.14) * time + length(o));
|
|
86
|
+
|
|
87
|
+
let n = fbm6_2(3.0 * o_mod);
|
|
88
|
+
|
|
89
|
+
let f = 0.5 + 0.5 * fbm4(1.8 * q_mod + 6.0 * n);
|
|
90
|
+
|
|
91
|
+
let result = mix(f, f * f * f * 3.5, f * abs(n.x));
|
|
92
|
+
|
|
93
|
+
return vec4<f32>(o, n.x, n.y);
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
@fragment
|
|
97
|
+
fn main(@location(0) ndc: vec2<f32>) -> @location(0) vec4<f32> {
|
|
98
|
+
let time = u.time.x;
|
|
99
|
+
let intensity = u.params0.x;
|
|
100
|
+
|
|
101
|
+
let resolution = u.resolution.xy;
|
|
102
|
+
let aspect = u.resolution.z;
|
|
103
|
+
|
|
104
|
+
var p = ndc;
|
|
105
|
+
p.y *= aspect;
|
|
106
|
+
|
|
107
|
+
let e = 2.0 / resolution.y;
|
|
108
|
+
|
|
109
|
+
let on = func(p, time);
|
|
110
|
+
|
|
111
|
+
let o = on.xy;
|
|
112
|
+
let n = on.zw;
|
|
113
|
+
|
|
114
|
+
var q = p;
|
|
115
|
+
q += 0.03 * sin(vec2<f32>(0.27, 0.23) * time + length(q) * vec2<f32>(4.1, 4.3));
|
|
116
|
+
let fbm_val = 0.5 + 0.5 * fbm4(1.8 * q + 6.0 * n);
|
|
117
|
+
let f = mix(fbm_val, fbm_val * fbm_val * fbm_val * 3.5, fbm_val * abs(n.x));
|
|
118
|
+
|
|
119
|
+
var col = vec3<f32>(0.0);
|
|
120
|
+
col = mix(vec3<f32>(0.2, 0.1, 0.4), vec3<f32>(0.3, 0.05, 0.05), f);
|
|
121
|
+
col = mix(col, vec3<f32>(0.9, 0.9, 0.9), dot(n, n));
|
|
122
|
+
col = mix(col, vec3<f32>(0.4, 0.3, 0.3), 0.2 + 0.5 * o.y * o.y);
|
|
123
|
+
col = mix(col, vec3<f32>(0.0, 0.2, 0.4), 0.5 * smoothstep(1.2, 1.3, abs(n.x) + abs(n.y)));
|
|
124
|
+
col = clamp(col * f * 2.0, vec3<f32>(0.0), vec3<f32>(1.0));
|
|
125
|
+
|
|
126
|
+
let kk1 = func(p + vec2<f32>(e, 0.0), time);
|
|
127
|
+
let kk2 = func(p + vec2<f32>(0.0, e), time);
|
|
128
|
+
|
|
129
|
+
var q1 = p + vec2<f32>(e, 0.0);
|
|
130
|
+
q1 += 0.03 * sin(vec2<f32>(0.27, 0.23) * time + length(q1) * vec2<f32>(4.1, 4.3));
|
|
131
|
+
let f1 = 0.5 + 0.5 * fbm4(1.8 * q1 + 6.0 * kk1.zw);
|
|
132
|
+
let fx = mix(f1, f1 * f1 * f1 * 3.5, f1 * abs(kk1.z));
|
|
133
|
+
|
|
134
|
+
var q2 = p + vec2<f32>(0.0, e);
|
|
135
|
+
q2 += 0.03 * sin(vec2<f32>(0.27, 0.23) * time + length(q2) * vec2<f32>(4.1, 4.3));
|
|
136
|
+
let f2 = 0.5 + 0.5 * fbm4(1.8 * q2 + 6.0 * kk2.zw);
|
|
137
|
+
let fy = mix(f2, f2 * f2 * f2 * 3.5, f2 * abs(kk2.z));
|
|
138
|
+
|
|
139
|
+
let nor = normalize(vec3<f32>(fx - f, 2.0 * e, fy - f));
|
|
140
|
+
|
|
141
|
+
let lig = normalize(vec3<f32>(0.9, 0.2, -0.4));
|
|
142
|
+
let dif = clamp(0.3 + 0.7 * dot(nor, lig), 0.0, 1.0);
|
|
143
|
+
let lin = vec3<f32>(0.70, 0.90, 0.95) * (nor.y * 0.5 + 0.5) + vec3<f32>(0.15, 0.10, 0.05) * dif;
|
|
144
|
+
col *= 1.2 * lin;
|
|
145
|
+
|
|
146
|
+
col = 1.0 - col;
|
|
147
|
+
col = 1.1 * col * col;
|
|
148
|
+
|
|
149
|
+
col = col * intensity;
|
|
150
|
+
col = col * u.color0.rgb;
|
|
151
|
+
|
|
152
|
+
return vec4<f32>(col, u.color0.a);
|
|
153
|
+
}
|
|
154
|
+
`;
|
|
155
|
+
//# sourceMappingURL=CalicoSwirl.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"names":["useMemo","ShaderView","jsx","_jsx","CalicoSwirl","color","speed","intensity","viewProps","colors","params","fragmentShader","CALICO_SWIRL_SHADER","isStatic"],"sourceRoot":"../../../src","sources":["components/CalicoSwirl.tsx"],"mappings":";;AAAA,SAASA,OAAO,QAAQ,OAAO;AAG/B,OAAOC,UAAU,MAAM,uBAAc;AAAC,SAAAC,GAAA,IAAAC,IAAA;AAWtC,eAAe,SAASC,WAAWA,CAAC;EAClCC,KAAK,GAAG,SAAS;EACjBC,KAAK,GAAG,GAAG;EACXC,SAAS,GAAG,GAAG;EACf,GAAGC;AACE,CAAC,EAAE;EACR,MAAMC,MAAM,GAAGT,OAAO,CAAC,MAAM,CAACK,KAAK,CAAC,EAAE,CAACA,KAAK,CAAC,CAAC;EAC9C,MAAMK,MAAM,GAAGV,OAAO,CAAC,MAAM,CAACO,SAAS,CAAC,EAAE,CAACA,SAAS,CAAC,CAAC;EAEtD,oBACEJ,IAAA,CAACF,UAAU;IACTU,cAAc,EAAEC,mBAAoB;IACpCH,MAAM,EAAEA,MAAO;IACfC,MAAM,EAAEA,MAAO;IACfJ,KAAK,EAAEA,KAAM;IACbO,QAAQ,EAAE,KAAM;IAAA,GACZL;EAAS,CACd,CAAC;AAEN;AAEA,MAAMI,mBAAmB,GAAG,UAAW;AACvC;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA;AACA,CAAC","ignoreList":[]}
|