react-native-effects 0.0.1 → 0.1.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 +251 -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 +224 -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/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/useWGPUSetup.js +54 -0
- package/lib/module/hooks/useWGPUSetup.js.map +1 -0
- package/lib/module/index.js +13 -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 +20 -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 +15 -0
- package/lib/typescript/src/components/ShaderView/types.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/useWGPUSetup.d.ts +15 -0
- package/lib/typescript/src/hooks/useWGPUSetup.d.ts.map +1 -0
- package/lib/typescript/src/index.d.ts +12 -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 +174 -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 +225 -0
- package/src/components/ShaderView/types.ts +15 -0
- package/src/components/Silk.tsx +102 -0
- package/src/consts.ts +152 -0
- package/src/hooks/useClock.ts +20 -0
- package/src/hooks/useWGPUSetup.tsx +73 -0
- package/src/index.tsx +23 -0
- package/src/shaders/TRIANGLE_VERTEX_SHADER.ts +17 -0
- package/src/shaders/uniforms.ts +17 -0
- package/src/utils/backgroundRuntime.ts +10 -0
- package/src/utils/colors.ts +117 -0
- package/src/utils/initWebGPU.ts +47 -0
package/package.json
CHANGED
|
@@ -1,12 +1,179 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "react-native-effects",
|
|
3
|
-
"version": "0.0
|
|
4
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "WebGPU-powered visual effects running on a background thread in React Native",
|
|
5
|
+
"main": "./lib/module/index.js",
|
|
6
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
7
|
+
"exports": {
|
|
8
|
+
".": {
|
|
9
|
+
"source": "./src/index.tsx",
|
|
10
|
+
"types": "./lib/typescript/src/index.d.ts",
|
|
11
|
+
"default": "./lib/module/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./package.json": "./package.json"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
"src",
|
|
17
|
+
"lib",
|
|
18
|
+
"android",
|
|
19
|
+
"ios",
|
|
20
|
+
"cpp",
|
|
21
|
+
"*.podspec",
|
|
22
|
+
"react-native.config.js",
|
|
23
|
+
"!ios/build",
|
|
24
|
+
"!android/build",
|
|
25
|
+
"!android/gradle",
|
|
26
|
+
"!android/gradlew",
|
|
27
|
+
"!android/gradlew.bat",
|
|
28
|
+
"!android/local.properties",
|
|
29
|
+
"!**/__tests__",
|
|
30
|
+
"!**/__fixtures__",
|
|
31
|
+
"!**/__mocks__",
|
|
32
|
+
"!**/.*"
|
|
33
|
+
],
|
|
5
34
|
"scripts": {
|
|
6
|
-
"
|
|
35
|
+
"example": "yarn workspace react-native-effects-example",
|
|
36
|
+
"clean": "del-cli lib",
|
|
37
|
+
"prepare": "bob build",
|
|
38
|
+
"typecheck": "tsc",
|
|
39
|
+
"lint": "eslint \"**/*.{js,ts,tsx}\"",
|
|
40
|
+
"test": "jest",
|
|
41
|
+
"prettier": "prettier --check \"**/*.{js,ts,tsx,json,md}\"",
|
|
42
|
+
"prettier:write": "prettier --write \"**/*.{js,ts,tsx,json,md}\"",
|
|
43
|
+
"release": "release-it --only-version"
|
|
44
|
+
},
|
|
45
|
+
"keywords": [
|
|
46
|
+
"react-native",
|
|
47
|
+
"ios",
|
|
48
|
+
"android",
|
|
49
|
+
"webgpu",
|
|
50
|
+
"glb",
|
|
51
|
+
"gltf",
|
|
52
|
+
"worklets"
|
|
53
|
+
],
|
|
54
|
+
"repository": {
|
|
55
|
+
"type": "git",
|
|
56
|
+
"url": "git+https://github.com/blazejkustra/react-native-effects.git"
|
|
57
|
+
},
|
|
58
|
+
"author": "Blazej Kustra <kustrablazej@gmail.com> (https://github.com/blazejkustra)",
|
|
59
|
+
"license": "MIT",
|
|
60
|
+
"bugs": {
|
|
61
|
+
"url": "https://github.com/blazejkustra/react-native-effects/issues"
|
|
62
|
+
},
|
|
63
|
+
"homepage": "https://github.com/blazejkustra/react-native-effects#readme",
|
|
64
|
+
"publishConfig": {
|
|
65
|
+
"registry": "https://registry.npmjs.org/"
|
|
66
|
+
},
|
|
67
|
+
"devDependencies": {
|
|
68
|
+
"@commitlint/config-conventional": "^19.8.1",
|
|
69
|
+
"@eslint/compat": "^1.3.2",
|
|
70
|
+
"@eslint/eslintrc": "^3.3.1",
|
|
71
|
+
"@eslint/js": "^9.35.0",
|
|
72
|
+
"@react-native/babel-preset": "0.83.1",
|
|
73
|
+
"@react-native/eslint-config": "0.83.1",
|
|
74
|
+
"@release-it/conventional-changelog": "^10.0.1",
|
|
75
|
+
"@types/jest": "^29.5.14",
|
|
76
|
+
"@types/react": "^19.1.12",
|
|
77
|
+
"@webgpu/types": "0.1.69",
|
|
78
|
+
"commitlint": "^19.8.1",
|
|
79
|
+
"del-cli": "^6.0.0",
|
|
80
|
+
"eslint": "^9.35.0",
|
|
81
|
+
"eslint-config-prettier": "^10.1.8",
|
|
82
|
+
"eslint-plugin-prettier": "^5.5.4",
|
|
83
|
+
"jest": "^29.7.0",
|
|
84
|
+
"lefthook": "^2.0.3",
|
|
85
|
+
"prettier": "^2.8.8",
|
|
86
|
+
"react": "19.2.0",
|
|
87
|
+
"react-native": "0.83.1",
|
|
88
|
+
"react-native-builder-bob": "^0.40.18",
|
|
89
|
+
"react-native-gesture-handler": "2.30.0",
|
|
90
|
+
"react-native-reanimated": "4.3.0-rc.0",
|
|
91
|
+
"react-native-wgpu": "0.5.6",
|
|
92
|
+
"react-native-worklets": "0.8.0-rc.0",
|
|
93
|
+
"release-it": "^19.0.4",
|
|
94
|
+
"turbo": "^2.5.6",
|
|
95
|
+
"typescript": "^5.9.2"
|
|
96
|
+
},
|
|
97
|
+
"peerDependencies": {
|
|
98
|
+
"react": "*",
|
|
99
|
+
"react-native": "*",
|
|
100
|
+
"react-native-gesture-handler": ">=2.0.0",
|
|
101
|
+
"react-native-wgpu": ">=0.5.0",
|
|
102
|
+
"react-native-worklets": ">=0.8.0"
|
|
103
|
+
},
|
|
104
|
+
"resolutions": {
|
|
105
|
+
"metro": "patch:metro@npm%3A0.83.3#./.yarn/patches/metro-npm-0.83.3-d09f48ca84.patch",
|
|
106
|
+
"metro-runtime": "patch:metro-runtime@npm%3A0.83.3#./.yarn/patches/metro-runtime-npm-0.83.3-c614bbd3b9.patch"
|
|
107
|
+
},
|
|
108
|
+
"workspaces": [
|
|
109
|
+
"example"
|
|
110
|
+
],
|
|
111
|
+
"packageManager": "yarn@4.11.0",
|
|
112
|
+
"react-native-builder-bob": {
|
|
113
|
+
"source": "src",
|
|
114
|
+
"output": "lib",
|
|
115
|
+
"targets": [
|
|
116
|
+
[
|
|
117
|
+
"module",
|
|
118
|
+
{
|
|
119
|
+
"esm": true
|
|
120
|
+
}
|
|
121
|
+
],
|
|
122
|
+
[
|
|
123
|
+
"typescript",
|
|
124
|
+
{
|
|
125
|
+
"project": "tsconfig.build.json"
|
|
126
|
+
}
|
|
127
|
+
]
|
|
128
|
+
]
|
|
129
|
+
},
|
|
130
|
+
"prettier": {
|
|
131
|
+
"quoteProps": "consistent",
|
|
132
|
+
"singleQuote": true,
|
|
133
|
+
"tabWidth": 2,
|
|
134
|
+
"trailingComma": "es5",
|
|
135
|
+
"useTabs": false
|
|
136
|
+
},
|
|
137
|
+
"jest": {
|
|
138
|
+
"preset": "react-native",
|
|
139
|
+
"modulePathIgnorePatterns": [
|
|
140
|
+
"<rootDir>/example/node_modules",
|
|
141
|
+
"<rootDir>/lib/"
|
|
142
|
+
]
|
|
143
|
+
},
|
|
144
|
+
"commitlint": {
|
|
145
|
+
"extends": [
|
|
146
|
+
"@commitlint/config-conventional"
|
|
147
|
+
]
|
|
148
|
+
},
|
|
149
|
+
"release-it": {
|
|
150
|
+
"git": {
|
|
151
|
+
"commitMessage": "chore: release ${version}",
|
|
152
|
+
"tagName": "v${version}"
|
|
153
|
+
},
|
|
154
|
+
"npm": {
|
|
155
|
+
"publish": true
|
|
156
|
+
},
|
|
157
|
+
"github": {
|
|
158
|
+
"release": true
|
|
159
|
+
},
|
|
160
|
+
"plugins": {
|
|
161
|
+
"@release-it/conventional-changelog": {
|
|
162
|
+
"preset": {
|
|
163
|
+
"name": "angular"
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
7
167
|
},
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
168
|
+
"create-react-native-library": {
|
|
169
|
+
"type": "library",
|
|
170
|
+
"languages": "js",
|
|
171
|
+
"tools": [
|
|
172
|
+
"eslint",
|
|
173
|
+
"jest",
|
|
174
|
+
"lefthook",
|
|
175
|
+
"release-it"
|
|
176
|
+
],
|
|
177
|
+
"version": "0.57.2"
|
|
178
|
+
}
|
|
12
179
|
}
|
|
@@ -0,0 +1,203 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import type { ViewProps } from 'react-native';
|
|
3
|
+
import type { ColorInput } from '../utils/colors';
|
|
4
|
+
import ShaderView from './ShaderView';
|
|
5
|
+
|
|
6
|
+
type Props = ViewProps & {
|
|
7
|
+
/** Base tint color for the aurora effect. */
|
|
8
|
+
color?: ColorInput;
|
|
9
|
+
/** Animation speed multiplier. Default: 1.0 */
|
|
10
|
+
speed?: number;
|
|
11
|
+
/** Brightness of the aurora bands. Default: 1.0 */
|
|
12
|
+
intensity?: number;
|
|
13
|
+
/** Number of aurora curtain layers (1-5). Default: 3 */
|
|
14
|
+
layers?: number;
|
|
15
|
+
/** How wavy/turbulent the curtains are. Default: 1.0 */
|
|
16
|
+
waviness?: number;
|
|
17
|
+
};
|
|
18
|
+
|
|
19
|
+
export default function Aurora({
|
|
20
|
+
color = '#4ade80',
|
|
21
|
+
speed = 1.0,
|
|
22
|
+
intensity = 1.0,
|
|
23
|
+
layers = 3.0,
|
|
24
|
+
waviness = 1.0,
|
|
25
|
+
...viewProps
|
|
26
|
+
}: Props) {
|
|
27
|
+
const colors = useMemo(() => [color], [color]);
|
|
28
|
+
const params = useMemo(
|
|
29
|
+
() => [intensity, layers, waviness],
|
|
30
|
+
[intensity, layers, waviness]
|
|
31
|
+
);
|
|
32
|
+
|
|
33
|
+
return (
|
|
34
|
+
<ShaderView
|
|
35
|
+
fragmentShader={AURORA_SHADER}
|
|
36
|
+
colors={colors}
|
|
37
|
+
params={params}
|
|
38
|
+
speed={speed}
|
|
39
|
+
isStatic={false}
|
|
40
|
+
{...viewProps}
|
|
41
|
+
/>
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
const AURORA_SHADER = /* wgsl */ `
|
|
46
|
+
struct Uniforms {
|
|
47
|
+
resolution: vec4<f32>,
|
|
48
|
+
time: vec4<f32>,
|
|
49
|
+
color0: vec4<f32>,
|
|
50
|
+
color1: vec4<f32>,
|
|
51
|
+
params0: vec4<f32>,
|
|
52
|
+
params1: vec4<f32>,
|
|
53
|
+
};
|
|
54
|
+
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
55
|
+
|
|
56
|
+
// Hash function for pseudo-random values
|
|
57
|
+
fn hash(p: vec2<f32>) -> f32 {
|
|
58
|
+
var p3 = fract(vec3<f32>(p.x, p.y, p.x) * 0.13);
|
|
59
|
+
p3 += dot(p3, vec3<f32>(p3.y + 3.333, p3.z + 3.333, p3.x + 3.333));
|
|
60
|
+
return fract((p3.x + p3.y) * p3.z);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
// 2D noise
|
|
64
|
+
fn noise(p: vec2<f32>) -> f32 {
|
|
65
|
+
let i = floor(p);
|
|
66
|
+
let f = fract(p);
|
|
67
|
+
let u_s = f * f * (3.0 - 2.0 * f);
|
|
68
|
+
|
|
69
|
+
let a = hash(i);
|
|
70
|
+
let b = hash(i + vec2<f32>(1.0, 0.0));
|
|
71
|
+
let c = hash(i + vec2<f32>(0.0, 1.0));
|
|
72
|
+
let d = hash(i + vec2<f32>(1.0, 1.0));
|
|
73
|
+
|
|
74
|
+
return mix(mix(a, b, u_s.x), mix(c, d, u_s.x), u_s.y);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// Fractional Brownian Motion
|
|
78
|
+
fn fbm(p_in: vec2<f32>, octaves: i32) -> f32 {
|
|
79
|
+
var p = p_in;
|
|
80
|
+
var value = 0.0;
|
|
81
|
+
var amplitude = 0.5;
|
|
82
|
+
var frequency = 1.0;
|
|
83
|
+
|
|
84
|
+
for (var i = 0; i < octaves; i++) {
|
|
85
|
+
value += amplitude * noise(p * frequency);
|
|
86
|
+
p = p * 2.01 + vec2<f32>(1.7, 9.2);
|
|
87
|
+
amplitude *= 0.5;
|
|
88
|
+
frequency *= 1.0;
|
|
89
|
+
}
|
|
90
|
+
return value;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
// Single aurora curtain layer
|
|
94
|
+
fn auroraLayer(uv: vec2<f32>, time: f32, offset: f32, waviness: f32) -> f32 {
|
|
95
|
+
// Horizontal position with time-based drift
|
|
96
|
+
let drift = time * 0.15 + offset * 2.5;
|
|
97
|
+
|
|
98
|
+
// Create the curtain shape using sine waves
|
|
99
|
+
let wave1 = sin(uv.x * 2.0 * waviness + drift + offset * 6.0) * 0.3;
|
|
100
|
+
let wave2 = sin(uv.x * 3.5 * waviness + drift * 1.3 + offset * 4.0) * 0.15;
|
|
101
|
+
let wave3 = sin(uv.x * 7.0 * waviness + drift * 0.7 + offset * 8.0) * 0.08;
|
|
102
|
+
|
|
103
|
+
// FBM noise for organic turbulence
|
|
104
|
+
let noiseVal = fbm(vec2<f32>(uv.x * 1.5 * waviness + drift * 0.5, uv.y * 0.8 + offset * 3.0), 4);
|
|
105
|
+
|
|
106
|
+
// Curtain center position (wavy vertical line)
|
|
107
|
+
let curtainCenter = 0.5 + wave1 + wave2 + wave3 + (noiseVal - 0.5) * 0.25 * waviness;
|
|
108
|
+
|
|
109
|
+
// Distance from curtain center for glow
|
|
110
|
+
let dist = abs(uv.y - curtainCenter);
|
|
111
|
+
|
|
112
|
+
// Soft glow falloff
|
|
113
|
+
let glow = exp(-dist * dist * 15.0) * 0.8;
|
|
114
|
+
|
|
115
|
+
// Add shimmer using noise
|
|
116
|
+
let shimmer = fbm(vec2<f32>(uv.x * 4.0 + time * 0.3, uv.y * 8.0 + offset * 5.0), 3);
|
|
117
|
+
let shimmerEffect = glow * (0.7 + 0.3 * shimmer);
|
|
118
|
+
|
|
119
|
+
// Fade toward bottom of screen (aurora appears in upper portion)
|
|
120
|
+
let heightFade = smoothstep(0.0, 0.6, uv.y);
|
|
121
|
+
|
|
122
|
+
return shimmerEffect * heightFade;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Stars in the background
|
|
126
|
+
fn stars(uv: vec2<f32>, time: f32) -> f32 {
|
|
127
|
+
let grid = floor(uv * 50.0);
|
|
128
|
+
let h = hash(grid);
|
|
129
|
+
|
|
130
|
+
// Only show some cells as stars
|
|
131
|
+
let star = step(0.92, h);
|
|
132
|
+
|
|
133
|
+
// Twinkle effect
|
|
134
|
+
let twinkle = 0.5 + 0.5 * sin(time * (1.0 + h * 3.0) + h * 6.28);
|
|
135
|
+
|
|
136
|
+
let cellUv = fract(uv * 50.0) - 0.5;
|
|
137
|
+
let d = length(cellUv);
|
|
138
|
+
let point = exp(-d * d * 80.0);
|
|
139
|
+
|
|
140
|
+
return point * star * twinkle * 0.6;
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
@fragment
|
|
144
|
+
fn main(@location(0) ndc: vec2<f32>) -> @location(0) vec4<f32> {
|
|
145
|
+
let time = u.time.x;
|
|
146
|
+
let intensity = u.params0.x;
|
|
147
|
+
let layerCount = u.params0.y;
|
|
148
|
+
let waviness = u.params0.z;
|
|
149
|
+
|
|
150
|
+
// Map NDC (-1..1) to UV (0..1)
|
|
151
|
+
let uv = ndc * 0.5 + 0.5;
|
|
152
|
+
|
|
153
|
+
// Dark sky background
|
|
154
|
+
let skyTop = vec3<f32>(0.0, 0.0, 0.02);
|
|
155
|
+
let skyBottom = vec3<f32>(0.01, 0.01, 0.04);
|
|
156
|
+
var col = mix(skyBottom, skyTop, uv.y);
|
|
157
|
+
|
|
158
|
+
// Add stars
|
|
159
|
+
let starVal = stars(uv, time);
|
|
160
|
+
// Dim stars where aurora is bright (computed later)
|
|
161
|
+
var auroraTotal = 0.0;
|
|
162
|
+
|
|
163
|
+
// Aurora color palette
|
|
164
|
+
let green = vec3<f32>(0.2, 0.9, 0.4);
|
|
165
|
+
let cyan = vec3<f32>(0.1, 0.7, 0.8);
|
|
166
|
+
let purple = vec3<f32>(0.5, 0.2, 0.8);
|
|
167
|
+
let pink = vec3<f32>(0.7, 0.2, 0.5);
|
|
168
|
+
|
|
169
|
+
// Accumulate aurora layers
|
|
170
|
+
let numLayers = i32(clamp(layerCount, 1.0, 5.0));
|
|
171
|
+
|
|
172
|
+
for (var i = 0; i < 5; i++) {
|
|
173
|
+
if (i >= numLayers) { break; }
|
|
174
|
+
|
|
175
|
+
let fi = f32(i);
|
|
176
|
+
let layerOffset = fi * 0.7;
|
|
177
|
+
|
|
178
|
+
let layer = auroraLayer(uv, time, layerOffset, waviness);
|
|
179
|
+
|
|
180
|
+
// Color varies per layer and position
|
|
181
|
+
let colorPhase = fi / f32(numLayers) + uv.x * 0.3 + time * 0.02;
|
|
182
|
+
let c1 = mix(green, cyan, sin(colorPhase * 3.14) * 0.5 + 0.5);
|
|
183
|
+
let c2 = mix(purple, pink, cos(colorPhase * 2.5) * 0.5 + 0.5);
|
|
184
|
+
let layerColor = mix(c1, c2, sin(colorPhase * 2.0 + fi) * 0.5 + 0.5);
|
|
185
|
+
|
|
186
|
+
col += layerColor * layer * intensity * (1.0 / f32(numLayers)) * 2.5;
|
|
187
|
+
auroraTotal += layer;
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// Add stars (dimmed where aurora is bright)
|
|
191
|
+
let starDim = max(0.0, 1.0 - auroraTotal * 2.0);
|
|
192
|
+
col += vec3<f32>(starVal * starDim);
|
|
193
|
+
|
|
194
|
+
// Apply tint color
|
|
195
|
+
col *= u.color0.rgb;
|
|
196
|
+
|
|
197
|
+
// Tone mapping - prevent over-saturation
|
|
198
|
+
col = col / (col + vec3<f32>(1.0));
|
|
199
|
+
col = pow(col, vec3<f32>(0.9));
|
|
200
|
+
|
|
201
|
+
return vec4<f32>(col, u.color0.a);
|
|
202
|
+
}
|
|
203
|
+
`;
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
import { useMemo } from 'react';
|
|
2
|
+
import type { ViewProps } from 'react-native';
|
|
3
|
+
import type { ColorInput } from '../utils/colors';
|
|
4
|
+
import ShaderView from './ShaderView';
|
|
5
|
+
|
|
6
|
+
type Props = ViewProps & {
|
|
7
|
+
/** The color tint for the calico swirl effect. */
|
|
8
|
+
color?: ColorInput;
|
|
9
|
+
/** Animation speed multiplier. Default: 1.0 */
|
|
10
|
+
speed?: number;
|
|
11
|
+
/** Intensity of the effect. Default: 1.0 */
|
|
12
|
+
intensity?: number;
|
|
13
|
+
};
|
|
14
|
+
|
|
15
|
+
export default function CalicoSwirl({
|
|
16
|
+
color = '#ffffff',
|
|
17
|
+
speed = 1.0,
|
|
18
|
+
intensity = 1.0,
|
|
19
|
+
...viewProps
|
|
20
|
+
}: Props) {
|
|
21
|
+
const colors = useMemo(() => [color], [color]);
|
|
22
|
+
const params = useMemo(() => [intensity], [intensity]);
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<ShaderView
|
|
26
|
+
fragmentShader={CALICO_SWIRL_SHADER}
|
|
27
|
+
colors={colors}
|
|
28
|
+
params={params}
|
|
29
|
+
speed={speed}
|
|
30
|
+
isStatic={false}
|
|
31
|
+
{...viewProps}
|
|
32
|
+
/>
|
|
33
|
+
);
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
const CALICO_SWIRL_SHADER = /* wgsl */ `
|
|
37
|
+
struct Uniforms {
|
|
38
|
+
resolution: vec4<f32>,
|
|
39
|
+
time: vec4<f32>,
|
|
40
|
+
color0: vec4<f32>,
|
|
41
|
+
color1: vec4<f32>,
|
|
42
|
+
params0: vec4<f32>,
|
|
43
|
+
params1: vec4<f32>,
|
|
44
|
+
};
|
|
45
|
+
@group(0) @binding(0) var<uniform> u: Uniforms;
|
|
46
|
+
|
|
47
|
+
const m = mat2x2<f32>(0.80, 0.60, -0.60, 0.80);
|
|
48
|
+
|
|
49
|
+
fn noise(p: vec2<f32>) -> f32 {
|
|
50
|
+
return sin(p.x) * sin(p.y);
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
fn fbm4(p_in: vec2<f32>) -> f32 {
|
|
54
|
+
var p = p_in;
|
|
55
|
+
var f = 0.0;
|
|
56
|
+
f += 0.5000 * noise(p);
|
|
57
|
+
p = m * p * 2.02;
|
|
58
|
+
f += 0.2500 * noise(p);
|
|
59
|
+
p = m * p * 2.03;
|
|
60
|
+
f += 0.1250 * noise(p);
|
|
61
|
+
p = m * p * 2.01;
|
|
62
|
+
f += 0.0625 * noise(p);
|
|
63
|
+
return f / 0.9375;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
fn fbm6(p_in: vec2<f32>) -> f32 {
|
|
67
|
+
var p = p_in;
|
|
68
|
+
var f = 0.0;
|
|
69
|
+
f += 0.500000 * (0.5 + 0.5 * noise(p));
|
|
70
|
+
p = m * p * 2.02;
|
|
71
|
+
f += 0.250000 * (0.5 + 0.5 * noise(p));
|
|
72
|
+
p = m * p * 2.03;
|
|
73
|
+
f += 0.125000 * (0.5 + 0.5 * noise(p));
|
|
74
|
+
p = m * p * 2.01;
|
|
75
|
+
f += 0.062500 * (0.5 + 0.5 * noise(p));
|
|
76
|
+
p = m * p * 2.04;
|
|
77
|
+
f += 0.031250 * (0.5 + 0.5 * noise(p));
|
|
78
|
+
p = m * p * 2.01;
|
|
79
|
+
f += 0.015625 * (0.5 + 0.5 * noise(p));
|
|
80
|
+
return f / 0.96875;
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
fn fbm4_2(p: vec2<f32>) -> vec2<f32> {
|
|
84
|
+
return vec2<f32>(fbm4(p), fbm4(p + vec2<f32>(7.8)));
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
fn fbm6_2(p: vec2<f32>) -> vec2<f32> {
|
|
88
|
+
return vec2<f32>(fbm6(p + vec2<f32>(16.8)), fbm6(p + vec2<f32>(11.5)));
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
fn func(q: vec2<f32>, time: f32) -> vec4<f32> {
|
|
92
|
+
var q_mod = q;
|
|
93
|
+
q_mod += 0.03 * sin(vec2<f32>(0.27, 0.23) * time + length(q) * vec2<f32>(4.1, 4.3));
|
|
94
|
+
|
|
95
|
+
let o = fbm4_2(0.9 * q_mod);
|
|
96
|
+
|
|
97
|
+
var o_mod = o;
|
|
98
|
+
o_mod += 0.04 * sin(vec2<f32>(0.12, 0.14) * time + length(o));
|
|
99
|
+
|
|
100
|
+
let n = fbm6_2(3.0 * o_mod);
|
|
101
|
+
|
|
102
|
+
let f = 0.5 + 0.5 * fbm4(1.8 * q_mod + 6.0 * n);
|
|
103
|
+
|
|
104
|
+
let result = mix(f, f * f * f * 3.5, f * abs(n.x));
|
|
105
|
+
|
|
106
|
+
return vec4<f32>(o, n.x, n.y);
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@fragment
|
|
110
|
+
fn main(@location(0) ndc: vec2<f32>) -> @location(0) vec4<f32> {
|
|
111
|
+
let time = u.time.x;
|
|
112
|
+
let intensity = u.params0.x;
|
|
113
|
+
|
|
114
|
+
let resolution = u.resolution.xy;
|
|
115
|
+
let aspect = u.resolution.z;
|
|
116
|
+
|
|
117
|
+
var p = ndc;
|
|
118
|
+
p.y *= aspect;
|
|
119
|
+
|
|
120
|
+
let e = 2.0 / resolution.y;
|
|
121
|
+
|
|
122
|
+
let on = func(p, time);
|
|
123
|
+
|
|
124
|
+
let o = on.xy;
|
|
125
|
+
let n = on.zw;
|
|
126
|
+
|
|
127
|
+
var q = p;
|
|
128
|
+
q += 0.03 * sin(vec2<f32>(0.27, 0.23) * time + length(q) * vec2<f32>(4.1, 4.3));
|
|
129
|
+
let fbm_val = 0.5 + 0.5 * fbm4(1.8 * q + 6.0 * n);
|
|
130
|
+
let f = mix(fbm_val, fbm_val * fbm_val * fbm_val * 3.5, fbm_val * abs(n.x));
|
|
131
|
+
|
|
132
|
+
var col = vec3<f32>(0.0);
|
|
133
|
+
col = mix(vec3<f32>(0.2, 0.1, 0.4), vec3<f32>(0.3, 0.05, 0.05), f);
|
|
134
|
+
col = mix(col, vec3<f32>(0.9, 0.9, 0.9), dot(n, n));
|
|
135
|
+
col = mix(col, vec3<f32>(0.4, 0.3, 0.3), 0.2 + 0.5 * o.y * o.y);
|
|
136
|
+
col = mix(col, vec3<f32>(0.0, 0.2, 0.4), 0.5 * smoothstep(1.2, 1.3, abs(n.x) + abs(n.y)));
|
|
137
|
+
col = clamp(col * f * 2.0, vec3<f32>(0.0), vec3<f32>(1.0));
|
|
138
|
+
|
|
139
|
+
let kk1 = func(p + vec2<f32>(e, 0.0), time);
|
|
140
|
+
let kk2 = func(p + vec2<f32>(0.0, e), time);
|
|
141
|
+
|
|
142
|
+
var q1 = p + vec2<f32>(e, 0.0);
|
|
143
|
+
q1 += 0.03 * sin(vec2<f32>(0.27, 0.23) * time + length(q1) * vec2<f32>(4.1, 4.3));
|
|
144
|
+
let f1 = 0.5 + 0.5 * fbm4(1.8 * q1 + 6.0 * kk1.zw);
|
|
145
|
+
let fx = mix(f1, f1 * f1 * f1 * 3.5, f1 * abs(kk1.z));
|
|
146
|
+
|
|
147
|
+
var q2 = p + vec2<f32>(0.0, e);
|
|
148
|
+
q2 += 0.03 * sin(vec2<f32>(0.27, 0.23) * time + length(q2) * vec2<f32>(4.1, 4.3));
|
|
149
|
+
let f2 = 0.5 + 0.5 * fbm4(1.8 * q2 + 6.0 * kk2.zw);
|
|
150
|
+
let fy = mix(f2, f2 * f2 * f2 * 3.5, f2 * abs(kk2.z));
|
|
151
|
+
|
|
152
|
+
let nor = normalize(vec3<f32>(fx - f, 2.0 * e, fy - f));
|
|
153
|
+
|
|
154
|
+
let lig = normalize(vec3<f32>(0.9, 0.2, -0.4));
|
|
155
|
+
let dif = clamp(0.3 + 0.7 * dot(nor, lig), 0.0, 1.0);
|
|
156
|
+
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;
|
|
157
|
+
col *= 1.2 * lin;
|
|
158
|
+
|
|
159
|
+
col = 1.0 - col;
|
|
160
|
+
col = 1.1 * col * col;
|
|
161
|
+
|
|
162
|
+
col = col * intensity;
|
|
163
|
+
col = col * u.color0.rgb;
|
|
164
|
+
|
|
165
|
+
return vec4<f32>(col, u.color0.a);
|
|
166
|
+
}
|
|
167
|
+
`;
|