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.
Files changed (110) hide show
  1. package/LICENSE +20 -0
  2. package/README.md +313 -0
  3. package/lib/module/components/Aurora.js +184 -0
  4. package/lib/module/components/Aurora.js.map +1 -0
  5. package/lib/module/components/CalicoSwirl.js +155 -0
  6. package/lib/module/components/CalicoSwirl.js.map +1 -0
  7. package/lib/module/components/Campfire.js +225 -0
  8. package/lib/module/components/Campfire.js.map +1 -0
  9. package/lib/module/components/CircularGradient.js +52 -0
  10. package/lib/module/components/CircularGradient.js.map +1 -0
  11. package/lib/module/components/Iridescence.js +57 -0
  12. package/lib/module/components/Iridescence.js.map +1 -0
  13. package/lib/module/components/LinearGradient.js +48 -0
  14. package/lib/module/components/LinearGradient.js.map +1 -0
  15. package/lib/module/components/LiquidChrome.js +75 -0
  16. package/lib/module/components/LiquidChrome.js.map +1 -0
  17. package/lib/module/components/ShaderView/index.js +252 -0
  18. package/lib/module/components/ShaderView/index.js.map +1 -0
  19. package/lib/module/components/ShaderView/types.js +4 -0
  20. package/lib/module/components/ShaderView/types.js.map +1 -0
  21. package/lib/module/components/ShaderViewWithPanGesture/index.js +196 -0
  22. package/lib/module/components/ShaderViewWithPanGesture/index.js.map +1 -0
  23. package/lib/module/components/Silk.js +83 -0
  24. package/lib/module/components/Silk.js.map +1 -0
  25. package/lib/module/consts.js +154 -0
  26. package/lib/module/consts.js.map +1 -0
  27. package/lib/module/hooks/useClock.js +15 -0
  28. package/lib/module/hooks/useClock.js.map +1 -0
  29. package/lib/module/hooks/useParamsSynchronizable.js +37 -0
  30. package/lib/module/hooks/useParamsSynchronizable.js.map +1 -0
  31. package/lib/module/hooks/useWGPUSetup.js +54 -0
  32. package/lib/module/hooks/useWGPUSetup.js.map +1 -0
  33. package/lib/module/index.js +15 -0
  34. package/lib/module/index.js.map +1 -0
  35. package/lib/module/package.json +1 -0
  36. package/lib/module/shaders/TRIANGLE_VERTEX_SHADER.js +20 -0
  37. package/lib/module/shaders/TRIANGLE_VERTEX_SHADER.js.map +1 -0
  38. package/lib/module/shaders/uniforms.js +21 -0
  39. package/lib/module/shaders/uniforms.js.map +1 -0
  40. package/lib/module/utils/backgroundRuntime.js +12 -0
  41. package/lib/module/utils/backgroundRuntime.js.map +1 -0
  42. package/lib/module/utils/colors.js +94 -0
  43. package/lib/module/utils/colors.js.map +1 -0
  44. package/lib/module/utils/initWebGPU.js +40 -0
  45. package/lib/module/utils/initWebGPU.js.map +1 -0
  46. package/lib/typescript/package.json +1 -0
  47. package/lib/typescript/src/components/Aurora.d.ts +17 -0
  48. package/lib/typescript/src/components/Aurora.d.ts.map +1 -0
  49. package/lib/typescript/src/components/CalicoSwirl.d.ts +13 -0
  50. package/lib/typescript/src/components/CalicoSwirl.d.ts.map +1 -0
  51. package/lib/typescript/src/components/Campfire.d.ts +17 -0
  52. package/lib/typescript/src/components/Campfire.d.ts.map +1 -0
  53. package/lib/typescript/src/components/CircularGradient.d.ts +19 -0
  54. package/lib/typescript/src/components/CircularGradient.d.ts.map +1 -0
  55. package/lib/typescript/src/components/Iridescence.d.ts +11 -0
  56. package/lib/typescript/src/components/Iridescence.d.ts.map +1 -0
  57. package/lib/typescript/src/components/LinearGradient.d.ts +15 -0
  58. package/lib/typescript/src/components/LinearGradient.d.ts.map +1 -0
  59. package/lib/typescript/src/components/LiquidChrome.d.ts +17 -0
  60. package/lib/typescript/src/components/LiquidChrome.d.ts.map +1 -0
  61. package/lib/typescript/src/components/ShaderView/index.d.ts +3 -0
  62. package/lib/typescript/src/components/ShaderView/index.d.ts.map +1 -0
  63. package/lib/typescript/src/components/ShaderView/types.d.ts +35 -0
  64. package/lib/typescript/src/components/ShaderView/types.d.ts.map +1 -0
  65. package/lib/typescript/src/components/ShaderViewWithPanGesture/index.d.ts +35 -0
  66. package/lib/typescript/src/components/ShaderViewWithPanGesture/index.d.ts.map +1 -0
  67. package/lib/typescript/src/components/Silk.d.ts +17 -0
  68. package/lib/typescript/src/components/Silk.d.ts.map +1 -0
  69. package/lib/typescript/src/consts.d.ts +2 -0
  70. package/lib/typescript/src/consts.d.ts.map +1 -0
  71. package/lib/typescript/src/hooks/useClock.d.ts +3 -0
  72. package/lib/typescript/src/hooks/useClock.d.ts.map +1 -0
  73. package/lib/typescript/src/hooks/useParamsSynchronizable.d.ts +22 -0
  74. package/lib/typescript/src/hooks/useParamsSynchronizable.d.ts.map +1 -0
  75. package/lib/typescript/src/hooks/useWGPUSetup.d.ts +15 -0
  76. package/lib/typescript/src/hooks/useWGPUSetup.d.ts.map +1 -0
  77. package/lib/typescript/src/index.d.ts +16 -0
  78. package/lib/typescript/src/index.d.ts.map +1 -0
  79. package/lib/typescript/src/shaders/TRIANGLE_VERTEX_SHADER.d.ts +2 -0
  80. package/lib/typescript/src/shaders/TRIANGLE_VERTEX_SHADER.d.ts.map +1 -0
  81. package/lib/typescript/src/shaders/uniforms.d.ts +6 -0
  82. package/lib/typescript/src/shaders/uniforms.d.ts.map +1 -0
  83. package/lib/typescript/src/utils/backgroundRuntime.d.ts +3 -0
  84. package/lib/typescript/src/utils/backgroundRuntime.d.ts.map +1 -0
  85. package/lib/typescript/src/utils/colors.d.ts +22 -0
  86. package/lib/typescript/src/utils/colors.d.ts.map +1 -0
  87. package/lib/typescript/src/utils/initWebGPU.d.ts +23 -0
  88. package/lib/typescript/src/utils/initWebGPU.d.ts.map +1 -0
  89. package/package.json +175 -7
  90. package/src/components/Aurora.tsx +203 -0
  91. package/src/components/CalicoSwirl.tsx +167 -0
  92. package/src/components/Campfire.tsx +244 -0
  93. package/src/components/CircularGradient.tsx +76 -0
  94. package/src/components/Iridescence.tsx +67 -0
  95. package/src/components/LinearGradient.tsx +62 -0
  96. package/src/components/LiquidChrome.tsx +94 -0
  97. package/src/components/ShaderView/index.tsx +262 -0
  98. package/src/components/ShaderView/types.ts +36 -0
  99. package/src/components/ShaderViewWithPanGesture/index.tsx +225 -0
  100. package/src/components/Silk.tsx +102 -0
  101. package/src/consts.ts +152 -0
  102. package/src/hooks/useClock.ts +20 -0
  103. package/src/hooks/useParamsSynchronizable.ts +52 -0
  104. package/src/hooks/useWGPUSetup.tsx +73 -0
  105. package/src/index.tsx +32 -0
  106. package/src/shaders/TRIANGLE_VERTEX_SHADER.ts +17 -0
  107. package/src/shaders/uniforms.ts +18 -0
  108. package/src/utils/backgroundRuntime.ts +10 -0
  109. package/src/utils/colors.ts +117 -0
  110. package/src/utils/initWebGPU.ts +47 -0
@@ -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
+ `;
@@ -0,0 +1,244 @@
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 fire effect. */
8
+ color?: ColorInput;
9
+ /** Animation speed multiplier. Default: 1.0 */
10
+ speed?: number;
11
+ /** Size of the sparks. Default: 1.0 */
12
+ sparkSize?: number;
13
+ /** Intensity of the fire. Default: 1.0 */
14
+ fireIntensity?: number;
15
+ /** Intensity of the smoke. Default: 1.0 */
16
+ smokeIntensity?: number;
17
+ };
18
+
19
+ export default function Campfire({
20
+ color = '#ffffff',
21
+ speed = 1.0,
22
+ sparkSize = 1.0,
23
+ fireIntensity = 1.0,
24
+ smokeIntensity = 1.0,
25
+ ...viewProps
26
+ }: Props) {
27
+ const colors = useMemo(() => [color], [color]);
28
+ const params = useMemo(
29
+ () => [sparkSize, fireIntensity, smokeIntensity],
30
+ [sparkSize, fireIntensity, smokeIntensity]
31
+ );
32
+
33
+ return (
34
+ <ShaderView
35
+ fragmentShader={CAMPFIRE_SHADER}
36
+ colors={colors}
37
+ params={params}
38
+ speed={speed}
39
+ isStatic={false}
40
+ {...viewProps}
41
+ />
42
+ );
43
+ }
44
+
45
+ const CAMPFIRE_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
+ fn mod289_3(x: vec3<f32>) -> vec3<f32> {
57
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
58
+ }
59
+
60
+ fn mod289_4(x: vec4<f32>) -> vec4<f32> {
61
+ return x - floor(x * (1.0 / 289.0)) * 289.0;
62
+ }
63
+
64
+ fn permute(x: vec4<f32>) -> vec4<f32> {
65
+ return mod289_4(((x * 34.0) + 1.0) * x);
66
+ }
67
+
68
+ fn taylorInvSqrt(r: vec4<f32>) -> vec4<f32> {
69
+ return 1.79284291400159 - 0.85373472095314 * r;
70
+ }
71
+
72
+ fn snoise(v: vec3<f32>) -> f32 {
73
+ let C = vec2<f32>(1.0 / 6.0, 1.0 / 3.0);
74
+ let D = vec4<f32>(0.0, 0.5, 1.0, 2.0);
75
+
76
+ var i = floor(v + dot(v, vec3<f32>(C.y, C.y, C.y)));
77
+ let x0 = v - i + dot(i, vec3<f32>(C.x, C.x, C.x));
78
+
79
+ let g = step(vec3<f32>(x0.y, x0.z, x0.x), x0);
80
+ let l = 1.0 - g;
81
+ let i1 = min(g, vec3<f32>(l.z, l.x, l.y));
82
+ let i2 = max(g, vec3<f32>(l.z, l.x, l.y));
83
+
84
+ let x1 = x0 - i1 + vec3<f32>(C.x, C.x, C.x);
85
+ let x2 = x0 - i2 + vec3<f32>(C.y, C.y, C.y);
86
+ let x3 = x0 - vec3<f32>(D.y, D.y, D.y);
87
+
88
+ i = mod289_3(i);
89
+ let p = permute(permute(permute(
90
+ i.z + vec4<f32>(0.0, i1.z, i2.z, 1.0))
91
+ + i.y + vec4<f32>(0.0, i1.y, i2.y, 1.0))
92
+ + i.x + vec4<f32>(0.0, i1.x, i2.x, 1.0));
93
+
94
+ let n_ = 0.142857142857;
95
+ let ns = n_ * vec3<f32>(D.w, D.y, D.z) - vec3<f32>(D.x, D.z, D.x);
96
+
97
+ let j = p - 49.0 * floor(p * ns.z * ns.z);
98
+
99
+ let x_ = floor(j * ns.z);
100
+ let y_ = floor(j - 7.0 * x_);
101
+
102
+ let x = x_ * ns.x + vec4<f32>(ns.y, ns.y, ns.y, ns.y);
103
+ let y = y_ * ns.x + vec4<f32>(ns.y, ns.y, ns.y, ns.y);
104
+ let h = 1.0 - abs(x) - abs(y);
105
+
106
+ let b0 = vec4<f32>(x.x, x.y, y.x, y.y);
107
+ let b1 = vec4<f32>(x.z, x.w, y.z, y.w);
108
+
109
+ let s0 = floor(b0) * 2.0 + 1.0;
110
+ let s1 = floor(b1) * 2.0 + 1.0;
111
+ let sh = -step(h, vec4<f32>(0.0));
112
+
113
+ let a0 = vec4<f32>(b0.x, b0.z, b0.y, b0.w) + vec4<f32>(s0.x, s0.z, s0.y, s0.w) * vec4<f32>(sh.x, sh.x, sh.y, sh.y);
114
+ let a1 = vec4<f32>(b1.x, b1.z, b1.y, b1.w) + vec4<f32>(s1.x, s1.z, s1.y, s1.w) * vec4<f32>(sh.z, sh.z, sh.w, sh.w);
115
+
116
+ let p0 = vec3<f32>(a0.x, a0.y, h.x);
117
+ let p1 = vec3<f32>(a0.z, a0.w, h.y);
118
+ let p2 = vec3<f32>(a1.x, a1.y, h.z);
119
+ let p3 = vec3<f32>(a1.z, a1.w, h.w);
120
+
121
+ let norm = inverseSqrt(vec4<f32>(dot(p0, p0), dot(p1, p1), dot(p2, p2), dot(p3, p3)));
122
+ let p0n = p0 * norm.x;
123
+ let p1n = p1 * norm.y;
124
+ let p2n = p2 * norm.z;
125
+ let p3n = p3 * norm.w;
126
+
127
+ var m = max(0.6 - vec4<f32>(dot(x0, x0), dot(x1, x1), dot(x2, x2), dot(x3, x3)), vec4<f32>(0.0));
128
+ m = m * m;
129
+ return 42.0 * dot(m * m, vec4<f32>(dot(p0n, x0), dot(p1n, x1), dot(p2n, x2), dot(p3n, x3)));
130
+ }
131
+
132
+ fn prng(seed: vec2<f32>) -> f32 {
133
+ var s = fract(seed * vec2<f32>(5.3983, 5.4427));
134
+ s = s + dot(vec2<f32>(s.y, s.x), s + vec2<f32>(21.5351, 14.3137));
135
+ return fract(s.x * s.y * 95.4337);
136
+ }
137
+
138
+ const PI = 3.1415926535897932384626433832795;
139
+
140
+ fn noiseStack(pos: vec3<f32>, octaves: i32, falloff: f32) -> f32 {
141
+ var noise = snoise(pos);
142
+ var off = 1.0;
143
+ var p = pos;
144
+
145
+ if (octaves > 1) {
146
+ p = p * 2.0;
147
+ off = off * falloff;
148
+ noise = (1.0 - off) * noise + off * snoise(p);
149
+ }
150
+ if (octaves > 2) {
151
+ p = p * 2.0;
152
+ off = off * falloff;
153
+ noise = (1.0 - off) * noise + off * snoise(p);
154
+ }
155
+ if (octaves > 3) {
156
+ p = p * 2.0;
157
+ off = off * falloff;
158
+ noise = (1.0 - off) * noise + off * snoise(p);
159
+ }
160
+ return (1.0 + noise) / 2.0;
161
+ }
162
+
163
+ fn noiseStackUV(pos: vec3<f32>, octaves: i32, falloff: f32) -> vec2<f32> {
164
+ let displaceA = noiseStack(pos, octaves, falloff);
165
+ let displaceB = noiseStack(pos + vec3<f32>(3984.293, 423.21, 5235.19), octaves, falloff);
166
+ return vec2<f32>(displaceA, displaceB);
167
+ }
168
+
169
+ @fragment
170
+ fn main(@location(0) ndc: vec2<f32>) -> @location(0) vec4<f32> {
171
+ let time = u.time.x;
172
+ let sparkSize = u.params0.x;
173
+ let fireIntensity = u.params0.y;
174
+ let smokeIntensity = u.params0.z;
175
+
176
+ let resolution = u.resolution.xy;
177
+ let vUv = ndc * 0.5 + vec2<f32>(0.5, 0.5);
178
+ let fragCoord = vUv * resolution;
179
+
180
+ let xpart = fragCoord.x / resolution.x;
181
+ let ypart = fragCoord.y / resolution.y;
182
+
183
+ let clip = 210.0;
184
+ let ypartClip = fragCoord.y / clip;
185
+ let ypartClippedFalloff = clamp(2.0 - ypartClip, 0.0, 1.0);
186
+ let ypartClipped = min(ypartClip, 1.0);
187
+ let ypartClippedn = 1.0 - ypartClipped;
188
+
189
+ let xfuel = 1.0 - abs(2.0 * xpart - 1.0);
190
+
191
+ let timeSpeed = 0.5;
192
+ let realTime = timeSpeed * time;
193
+
194
+ let coordScaled = 0.01 * fragCoord;
195
+ let position = vec3<f32>(coordScaled, 0.0) + vec3<f32>(1223.0, 6434.0, 8425.0);
196
+ let flow = vec3<f32>(4.1 * (0.5 - xpart) * pow(ypartClippedn, 4.0), -2.0 * xfuel * pow(ypartClippedn, 64.0), 0.0);
197
+ let timing = realTime * vec3<f32>(0.0, -1.7, 1.1) + flow;
198
+
199
+ let displacePos = vec3<f32>(1.0, 0.5, 1.0) * 2.4 * position + realTime * vec3<f32>(0.01, -0.7, 1.3);
200
+ let displace3 = vec3<f32>(noiseStackUV(displacePos, 2, 0.4), 0.0);
201
+
202
+ let noiseCoord = (vec3<f32>(2.0, 1.0, 1.0) * position + timing + 0.4 * displace3) / 1.0;
203
+ let noise = noiseStack(noiseCoord, 3, 0.4);
204
+
205
+ let flames = pow(ypartClipped, 0.3 * xfuel) * pow(noise, 0.3 * xfuel);
206
+
207
+ let f = ypartClippedFalloff * pow(1.0 - flames * flames * flames, 8.0);
208
+ let fff = f * f * f;
209
+ var fire = 1.5 * vec3<f32>(f, fff, fff * fff) * fireIntensity;
210
+
211
+ let smokeNoise = 0.5 + snoise(0.4 * position + timing * vec3<f32>(1.0, 1.0, 0.2)) / 2.0;
212
+ let smoke = vec3<f32>(0.3 * pow(xfuel, 3.0) * pow(ypart, 2.0) * (smokeNoise + 0.4 * (1.0 - noise))) * smokeIntensity;
213
+
214
+ let sparkGridSize = 30.0;
215
+ var sparkCoord = fragCoord - vec2<f32>(0.0, 190.0 * realTime);
216
+ sparkCoord = sparkCoord - 30.0 * noiseStackUV(0.01 * vec3<f32>(sparkCoord, 30.0 * time), 1, 0.4);
217
+ sparkCoord = sparkCoord + 100.0 * flow.xy;
218
+
219
+ if (sparkCoord.y / sparkGridSize % 2.0 < 1.0) {
220
+ sparkCoord.x = sparkCoord.x + 0.5 * sparkGridSize;
221
+ }
222
+
223
+ let sparkGridIndex = vec2<f32>(floor(sparkCoord / sparkGridSize));
224
+ let sparkRandom = prng(sparkGridIndex);
225
+ let sparkLife = min(10.0 * (1.0 - min((sparkGridIndex.y + (190.0 * realTime / sparkGridSize)) / (24.0 - 20.0 * sparkRandom), 1.0)), 1.0);
226
+
227
+ var sparks = vec3<f32>(0.0);
228
+ if (sparkLife > 0.0) {
229
+ let sparkSizeScaled = xfuel * xfuel * sparkRandom * 0.08 * sparkSize;
230
+ let sparkRadians = 999.0 * sparkRandom * 2.0 * PI + 2.0 * time;
231
+ let sparkCircular = vec2<f32>(sin(sparkRadians), cos(sparkRadians));
232
+ let sparkOffset = (0.5 - sparkSizeScaled) * sparkGridSize * sparkCircular;
233
+ let sparkModulus = (sparkCoord + sparkOffset) % sparkGridSize - 0.5 * vec2<f32>(sparkGridSize);
234
+ let sparkLength = length(sparkModulus);
235
+ let sparksGray = max(0.0, 1.0 - sparkLength / (sparkSizeScaled * sparkGridSize));
236
+ sparks = sparkLife * sparksGray * vec3<f32>(1.0, 0.3, 0.0);
237
+ }
238
+
239
+ fire = fire * u.color0.rgb;
240
+
241
+ let finalColor = max(fire, sparks) + smoke;
242
+ return vec4<f32>(clamp(finalColor, vec3<f32>(0.0), vec3<f32>(1.0)), u.color0.a);
243
+ }
244
+ `;
@@ -0,0 +1,76 @@
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 at the center of the gradient. */
8
+ centerColor: ColorInput;
9
+ /** The color at the edge of the gradient. Default: transparent */
10
+ edgeColor?: ColorInput;
11
+ /** Horizontal center position (0-1). Default: 0.5 */
12
+ centerX?: number;
13
+ /** Vertical center position (0-1). Default: 0.5 */
14
+ centerY?: number;
15
+ /** Horizontal radius. Default: 0.5 */
16
+ sizeX?: number;
17
+ /** Vertical radius. Default: 0.5 */
18
+ sizeY?: number;
19
+ };
20
+
21
+ export default function CircularGradient({
22
+ centerColor,
23
+ edgeColor = 'rgba(0,0,0,0)',
24
+ centerX = 0.5,
25
+ centerY = 0.5,
26
+ sizeX = 0.5,
27
+ sizeY = 0.5,
28
+ ...viewProps
29
+ }: Props) {
30
+ const colors = useMemo(
31
+ () => [centerColor, edgeColor],
32
+ [centerColor, edgeColor]
33
+ );
34
+ const params = useMemo(
35
+ () => [centerX, centerY, sizeX, sizeY],
36
+ [centerX, centerY, sizeX, sizeY]
37
+ );
38
+
39
+ return (
40
+ <ShaderView
41
+ fragmentShader={CIRCULAR_GRADIENT_SHADER}
42
+ colors={colors}
43
+ params={params}
44
+ isStatic={true}
45
+ {...viewProps}
46
+ />
47
+ );
48
+ }
49
+
50
+ const CIRCULAR_GRADIENT_SHADER = /* wgsl */ `
51
+ struct Uniforms {
52
+ resolution: vec4<f32>,
53
+ time: vec4<f32>,
54
+ color0: vec4<f32>,
55
+ color1: vec4<f32>,
56
+ params0: vec4<f32>,
57
+ params1: vec4<f32>,
58
+ };
59
+ @group(0) @binding(0) var<uniform> u: Uniforms;
60
+
61
+ @fragment
62
+ fn main(@location(0) ndc: vec2<f32>) -> @location(0) vec4<f32> {
63
+ let uv = (ndc * 0.5) + vec2<f32>(0.5, 0.5);
64
+
65
+ let center = u.params0.xy;
66
+ let size = u.params0.zw;
67
+
68
+ let diff = uv - center;
69
+ let normalizedDiff = diff / size;
70
+ let dist = length(normalizedDiff);
71
+
72
+ let t = smoothstep(0.0, 1.0, dist);
73
+ let color = mix(u.color0, u.color1, t);
74
+ return color;
75
+ }
76
+ `;