@firecms/neat 0.8.0 → 0.9.1

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/src/shaders.ts CHANGED
@@ -1,5 +1,6 @@
1
1
  export const vertexShaderSource = `void main() {
2
2
  vUv = uv;
3
+ vPosition = position;
3
4
 
4
5
  // SCROLLING LOGIC
5
6
  // Separate multipliers for wave, color, and flow offsets
@@ -41,11 +42,36 @@ export const vertexShaderSource = `void main() {
41
42
  // We take the computed flow UVs and apply the color offset
42
43
  // Scale by plane height to match wave offset speed (world space vs UV space)
43
44
  vec3 color = u_colors[0].color;
44
- // ...
45
- vec2 adjustedUv = flowUv;
46
- adjustedUv.y += colorOffset / u_plane_height; // Scroll the color mixing pattern
47
45
 
48
- vec2 noise_cord = adjustedUv * u_color_pressure;
46
+ vec3 distortedPos = position;
47
+ if (u_flat_shading < 0.5) {
48
+ if (u_flow_enabled > 0.5) {
49
+ if (u_flow_ease > 0.0 || u_flow_distortion_a > 0.0) {
50
+ vec3 ppp = position / 25.0;
51
+ ppp.xyz += 0.1 * cos((1.5 * u_flow_scale) * ppp.yxz + 1.1 * u_time + vec3(0.1, 1.1, 2.1));
52
+ ppp.xyz += 0.1 * cos((2.3 * u_flow_scale) * ppp.zxy + 1.3 * u_time + vec3(3.2, 3.4, 1.2));
53
+ ppp.xyz += 0.1 * cos((2.2 * u_flow_scale) * ppp.yxz + 1.7 * u_time + vec3(1.8, 5.2, 3.1));
54
+ ppp.xyz += u_flow_distortion_a * cos((u_flow_distortion_b * u_flow_scale) * ppp.zxy + 1.4 * u_time + vec3(6.3, 3.9, 4.5));
55
+
56
+ float r = length(ppp);
57
+ distortedPos = mix(position, vec3(
58
+ position.x * (1.0 - u_flow_ease) + r * u_flow_ease * 25.0,
59
+ position.y,
60
+ position.z * (1.0 - u_flow_ease) + r * u_flow_ease * 25.0
61
+ ), u_flow_ease);
62
+ }
63
+ }
64
+ }
65
+
66
+ vec3 noise_cord;
67
+ if (u_flat_shading < 0.5) {
68
+ noise_cord = vec3(distortedPos.x / 50.0, (distortedPos.y + colorOffset) / 50.0, distortedPos.z / 50.0);
69
+ } else {
70
+ vec2 adjustedUv = flowUv;
71
+ adjustedUv.y += colorOffset / u_plane_height;
72
+ noise_cord = vec3(adjustedUv, 0.0);
73
+ }
74
+
49
75
  const float minNoise = .0;
50
76
  const float maxNoise = .9;
51
77
 
@@ -56,11 +82,16 @@ export const vertexShaderSource = `void main() {
56
82
  float noiseSpeed = (1. + float(i)) * 0.11;
57
83
  float noiseSeed = 13. + float(i) * 7.;
58
84
 
85
+ float noise_z = u_time * noiseSpeed;
86
+ if (u_flat_shading < 0.5) {
87
+ noise_z = noise_cord.z * u_color_pressure.x * u_color_pressure.x + u_time * noiseSpeed;
88
+ }
89
+
59
90
  float noise = snoise(
60
91
  vec3(
61
- noise_cord.x * u_color_pressure.x + u_time * noiseFlow * 2.,
62
- noise_cord.y * u_color_pressure.y,
63
- u_time * noiseSpeed
92
+ noise_cord.x * u_color_pressure.x * u_color_pressure.x + u_time * noiseFlow * 2.,
93
+ noise_cord.y * u_color_pressure.y * u_color_pressure.y,
94
+ noise_z
64
95
  ) + noiseSeed
65
96
  ) - (.1 * float(i)) + (.5 * u_color_blending);
66
97
 
@@ -77,7 +108,10 @@ export const vertexShaderSource = `void main() {
77
108
 
78
109
  // 5. VERTEX POSITION
79
110
  vec3 newPosition = position + normal * v_displacement_amount * u_wave_amplitude;
80
- gl_Position = projectionMatrix * modelViewMatrix * vec4(newPosition, 1.0);
111
+ vec4 mvPosition = modelViewMatrix * vec4(newPosition, 1.0);
112
+ vViewPosition = mvPosition.xyz;
113
+ vNormal = normalize((modelViewMatrix * vec4(normal, 0.0)).xyz);
114
+ gl_Position = projectionMatrix * mvPosition;
81
115
  v_new_position = gl_Position;
82
116
  }
83
117
  `;
@@ -90,7 +124,7 @@ float fbm(vec3 x) {
90
124
  float value = 0.0;
91
125
  float amplitude = 0.5;
92
126
  float frequency = 1.0;
93
- for (int i = 0; i < 4; i++) {
127
+ for (int i = 0; i < 2; i++) {
94
128
  value += amplitude * snoise(x * frequency);
95
129
  frequency *= 2.0;
96
130
  amplitude *= 0.5;
@@ -108,25 +142,55 @@ void main() {
108
142
  vec2 finalUv = vFlowUv;
109
143
 
110
144
  vec3 baseColor;
145
+ float texAlpha = 1.0;
111
146
 
112
147
  if (u_enable_procedural_texture > 0.5) {
113
- vec2 ppp = -1.0 + 2.0 * finalUv;
114
- ppp += 0.1 * cos((1.5 * u_flow_scale) * ppp.yx + 1.1 * u_time + vec2(0.1, 1.1));
115
- ppp += 0.1 * cos((2.3 * u_flow_scale) * ppp.yx + 1.3 * u_time + vec2(3.2, 3.4));
116
- ppp += 0.1 * cos((2.2 * u_flow_scale) * ppp.yx + 1.7 * u_time + vec2(1.8, 5.2));
117
- ppp += u_flow_distortion_a * cos((u_flow_distortion_b * u_flow_scale) * ppp.yx + 1.4 * u_time + vec2(6.3, 3.9));
118
- float r = length(ppp);
119
-
120
- float vx = (finalUv.x * u_texture_ease) + (r * (1.0 - u_texture_ease));
121
- float vy = (finalUv.y * u_texture_ease) + (0.0 * (1.0 - u_texture_ease));
122
- vec2 texUv = vec2(vx, vy);
123
-
124
- float parallaxFactor = 0.25;
125
- texUv.y -= (u_y_offset * u_y_offset_color_multiplier / u_plane_height) * parallaxFactor;
126
- texUv *= 1.5;
127
-
128
- vec4 texSample = texture2D(u_procedural_texture, texUv);
129
- baseColor = texSample.rgb;
148
+ if (u_flat_shading < 0.5) {
149
+ float parallaxFactor = 0.25;
150
+ float scrollOffset = (u_y_offset * u_y_offset_color_multiplier) * parallaxFactor;
151
+ vec3 scrolledPos = vPosition;
152
+ scrolledPos.y -= scrollOffset;
153
+
154
+ vec3 p = (scrolledPos * 1.5) / 50.0;
155
+ vec2 uvX = p.yz + vec2(0.5);
156
+ vec2 uvY = p.zx + vec2(0.5);
157
+ vec2 uvZ = p.xy + vec2(0.5);
158
+
159
+ vec4 colX = texture2D(u_procedural_texture, uvX);
160
+ vec4 colY = texture2D(u_procedural_texture, uvY);
161
+ vec4 colZ = texture2D(u_procedural_texture, uvZ);
162
+
163
+ vec3 n = normalize(vNormal);
164
+ vec3 blendWeights = abs(n);
165
+ blendWeights = blendWeights / (blendWeights.x + blendWeights.y + blendWeights.z + 0.0001);
166
+
167
+ vec4 texSample = colX * blendWeights.x + colY * blendWeights.y + colZ * blendWeights.z;
168
+ baseColor = texSample.rgb;
169
+ if (u_transparent_texture_void > 0.5) {
170
+ texAlpha = texSample.a;
171
+ }
172
+ } else {
173
+ vec2 ppp = -1.0 + 2.0 * finalUv;
174
+ ppp += 0.1 * cos((1.5 * u_flow_scale) * ppp.yx + 1.1 * u_time + vec2(0.1, 1.1));
175
+ ppp += 0.1 * cos((2.3 * u_flow_scale) * ppp.yx + 1.3 * u_time + vec2(3.2, 3.4));
176
+ ppp += 0.1 * cos((2.2 * u_flow_scale) * ppp.yx + 1.7 * u_time + vec2(1.8, 5.2));
177
+ ppp += u_flow_distortion_a * cos((u_flow_distortion_b * u_flow_scale) * ppp.yx + 1.4 * u_time + vec2(6.3, 3.9));
178
+ float r = length(ppp);
179
+
180
+ float vx = (finalUv.x * u_texture_ease) + (r * (1.0 - u_texture_ease));
181
+ float vy = (finalUv.y * u_texture_ease) + (0.0 * (1.0 - u_texture_ease));
182
+ vec2 texUv = vec2(vx, vy);
183
+
184
+ float parallaxFactor = 0.25;
185
+ texUv.y -= (u_y_offset * u_y_offset_color_multiplier / u_plane_height) * parallaxFactor;
186
+ texUv *= 1.5;
187
+
188
+ vec4 texSample = texture2D(u_procedural_texture, texUv);
189
+ baseColor = texSample.rgb;
190
+ if (u_transparent_texture_void > 0.5) {
191
+ texAlpha = texSample.a;
192
+ }
193
+ }
130
194
  } else {
131
195
  baseColor = v_color;
132
196
  }
@@ -135,7 +199,13 @@ void main() {
135
199
 
136
200
  // === DOMAIN WARPING (simplified: 3 fbm calls instead of 5) ===
137
201
  if (u_domain_warp_enabled > 0.5) {
138
- vec3 p = vec3(finalUv * u_domain_warp_scale, u_time * 0.15);
202
+ vec3 p;
203
+ if (u_flat_shading < 0.5) {
204
+ p = vec3((vPosition / 50.0 + vec3(0.5)) * u_domain_warp_scale);
205
+ p.z += u_time * 0.15;
206
+ } else {
207
+ p = vec3(finalUv * u_domain_warp_scale, u_time * 0.15);
208
+ }
139
209
  vec2 q = vec2(fbm(p), fbm(p + vec3(5.2, 1.3, 0.0)));
140
210
  float f = fbm(p + vec3(4.0 * q, 0.0));
141
211
  vec3 warpColor = color * (1.0 + f * 0.8 * u_domain_warp_intensity);
@@ -144,9 +214,42 @@ void main() {
144
214
  }
145
215
 
146
216
  // Post-processing
147
- color += v_displacement_amount * u_highlights;
148
- float shadowFactor = 1.0 - v_displacement_amount;
149
- color -= shadowFactor * shadowFactor * u_shadows;
217
+ // Compute dynamic pixel-perfect normal using smooth normal
218
+ vec3 normal = normalize(vNormal);
219
+ vec3 viewDir = vec3(0.0, 0.0, 1.0);
220
+ float ndotv = dot(normal, viewDir);
221
+
222
+ // Cull back-faces for closed 3D shapes (Sphere=1, Torus=2, Cylinder=3)
223
+ if (u_shape_type > 0.5 && u_shape_type < 3.5) {
224
+ if (ndotv < 0.0) {
225
+ discard;
226
+ }
227
+ } else {
228
+ // Double-sided shapes (Plane, Ribbon): flip normal if back-facing
229
+ if (ndotv < 0.0) {
230
+ normal = -normal;
231
+ ndotv = -ndotv;
232
+ }
233
+ }
234
+ vec3 lightDir = normalize(vec3(1.0, 1.0, 1.0));
235
+ float diffuse = max(dot(normal, lightDir), 0.0);
236
+ vec3 halfDir = normalize(lightDir + viewDir);
237
+ float specular = pow(max(dot(normal, halfDir), 0.0), 32.0);
238
+
239
+ // Blend smooth 3D shading with smooth height-based wave shading
240
+ if (u_flat_shading > 0.5) {
241
+ // Flat / height-based wave shading (plane style)
242
+ color += v_displacement_amount * u_highlights;
243
+ float heightShadow = 1.0 - v_displacement_amount;
244
+ color -= heightShadow * heightShadow * u_shadows;
245
+ } else {
246
+ // 3D shading
247
+ color += specular * u_highlights;
248
+ color += v_displacement_amount * u_highlights * 0.5;
249
+ float heightShadow = 1.0 - v_displacement_amount;
250
+ color -= heightShadow * heightShadow * u_shadows * 0.5;
251
+ color -= (1.0 - diffuse) * u_shadows * 0.5;
252
+ }
150
253
  color = saturation(color, 1.0 + u_saturation);
151
254
  color = color * u_brightness;
152
255
 
@@ -166,7 +269,11 @@ void main() {
166
269
 
167
270
  // === VIGNETTE ===
168
271
  if (u_vignette_intensity > 0.0) {
169
- float dist = length(vUv - vec2(0.5));
272
+ vec2 vigUv = vUv;
273
+ if (u_flat_shading < 0.5) {
274
+ vigUv = (v_new_position.xy / v_new_position.w) * 0.5 + vec2(0.5);
275
+ }
276
+ float dist = length(vigUv - vec2(0.5));
170
277
  float vig = smoothstep(u_vignette_radius, u_vignette_radius * 0.3, dist);
171
278
  color *= mix(1.0, vig, u_vignette_intensity);
172
279
  }
@@ -181,7 +288,11 @@ void main() {
181
288
  // === CHROMATIC ABERRATION ===
182
289
  if (u_chromatic_aberration > 0.0) {
183
290
  float caAmount = u_chromatic_aberration * 0.008;
184
- float dist = length(vUv - vec2(0.5));
291
+ vec2 caUv = vUv;
292
+ if (u_flat_shading < 0.5) {
293
+ caUv = (v_new_position.xy / v_new_position.w) * 0.5 + vec2(0.5);
294
+ }
295
+ float dist = length(caUv - vec2(0.5));
185
296
  float rShift = v_displacement_amount + caAmount * dist;
186
297
  float bShift = v_displacement_amount - caAmount * dist;
187
298
  color.r *= 1.0 + rShift * caAmount * 10.0;
@@ -192,7 +303,7 @@ void main() {
192
303
  float grain = 0.0;
193
304
  if (u_grain_intensity > 0.0) {
194
305
  vec2 noiseCoords = gl_FragCoord.xy / u_grain_scale;
195
- if (u_grain_speed != 0.0) {
306
+ if (u_grain_speed != 0.0 || u_flat_shading > 0.5) {
196
307
  grain = fbm(vec3(noiseCoords, u_time * u_grain_speed));
197
308
  } else {
198
309
  // Static grain: use cheap hash instead of fbm
@@ -207,7 +318,25 @@ void main() {
207
318
 
208
319
  color += vec3(grain);
209
320
 
210
- gl_FragColor = vec4(color, 1.0);
321
+ float edgeAlpha = 1.0;
322
+
323
+ // Silhouette falloff for 3D shapes (skip when flat shading or fade is zero)
324
+ if (u_silhouette_fade > 0.0 && u_flat_shading < 0.5) {
325
+ edgeAlpha = smoothstep(0.0, u_silhouette_fade, ndotv);
326
+ }
327
+
328
+ // UV boundary falloff for open shapes
329
+ if (u_shape_type == 3.0) { // Cylinder: fade top/bottom ends
330
+ float vFade = smoothstep(0.0, u_cylinder_fade, vUv.y) * smoothstep(1.0, 1.0 - u_cylinder_fade, vUv.y);
331
+ edgeAlpha *= vFade;
332
+ } else if (u_shape_type == 4.0) { // Ribbon: fade all 4 borders
333
+ float uFade = smoothstep(0.0, u_ribbon_fade, vUv.x) * smoothstep(1.0, 1.0 - u_ribbon_fade, vUv.x);
334
+ float vFade = smoothstep(0.0, u_ribbon_fade, vUv.y) * smoothstep(1.0, 1.0 - u_ribbon_fade, vUv.y);
335
+ edgeAlpha *= uFade * vFade;
336
+ }
337
+
338
+ edgeAlpha *= texAlpha;
339
+ gl_FragColor = vec4(color, edgeAlpha);
211
340
  }
212
341
  `;
213
342
 
@@ -226,6 +355,9 @@ varying vec2 vFlowUv;
226
355
  varying vec4 v_new_position;
227
356
  varying vec3 v_color;
228
357
  varying float v_displacement_amount;
358
+ varying vec3 vViewPosition;
359
+ varying vec3 vNormal;
360
+ varying vec3 vPosition;
229
361
 
230
362
  uniform float u_time;
231
363
  uniform vec2 u_resolution;
@@ -262,6 +394,9 @@ uniform float u_fresnel_enabled;
262
394
  uniform float u_fresnel_power;
263
395
  uniform float u_fresnel_intensity;
264
396
  uniform vec3 u_fresnel_color;
397
+
398
+ uniform float u_shape_type;
399
+ uniform float u_flat_shading;
265
400
  `;
266
401
  }
267
402
 
@@ -270,8 +405,12 @@ export function buildFragUniforms(): string {
270
405
 
271
406
  varying vec2 vUv;
272
407
  varying vec2 vFlowUv;
408
+ varying vec4 v_new_position;
273
409
  varying vec3 v_color;
274
410
  varying float v_displacement_amount;
411
+ varying vec3 vViewPosition;
412
+ varying vec3 vNormal;
413
+ varying vec3 vPosition;
275
414
 
276
415
  uniform float u_time;
277
416
  uniform vec2 u_resolution;
@@ -327,6 +466,12 @@ uniform float u_bloom_threshold;
327
466
 
328
467
  // Chromatic aberration
329
468
  uniform float u_chromatic_aberration;
469
+ uniform float u_shape_type;
470
+ uniform float u_transparent_texture_void;
471
+ uniform float u_silhouette_fade;
472
+ uniform float u_cylinder_fade;
473
+ uniform float u_ribbon_fade;
474
+ uniform float u_flat_shading;
330
475
  `;
331
476
  }
332
477
 
package/src/types.ts CHANGED
@@ -68,6 +68,36 @@ export type NeatConfig = {
68
68
 
69
69
  // Chromatic aberration
70
70
  chromaticAberration?: number;
71
+
72
+ // 3D Shapes config
73
+ shapeType?: 'plane' | 'sphere' | 'torus' | 'cylinder' | 'ribbon';
74
+ shapeRotationX?: number;
75
+ shapeRotationY?: number;
76
+ shapeRotationZ?: number;
77
+ shapeAutoRotateSpeedX?: number;
78
+ shapeAutoRotateSpeedY?: number;
79
+ sphereRadius?: number;
80
+ torusRadius?: number;
81
+ torusTube?: number;
82
+ cylinderRadius?: number;
83
+ cylinderHeight?: number;
84
+ planeBend?: number;
85
+ planeTwist?: number;
86
+ transparentTextureVoid?: boolean;
87
+ flatShading?: boolean;
88
+ silhouetteFade?: number;
89
+ cylinderFade?: number;
90
+ ribbonFade?: number;
91
+
92
+ // Camera settings
93
+ cameraLock?: boolean;
94
+ cameraX?: number;
95
+ cameraY?: number;
96
+ cameraZ?: number;
97
+ cameraRotationX?: number;
98
+ cameraRotationY?: number;
99
+ cameraRotationZ?: number;
100
+ cameraZoom?: number;
71
101
  };
72
102
 
73
103
  export type NeatColor = {