@razorpay/blade 12.92.0 → 12.93.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 (112) hide show
  1. package/assets/spark/bottom-frame.jpg +0 -0
  2. package/assets/spark/colorama-center-gradient-map.jpg +0 -0
  3. package/assets/spark/colorama-gradient-map-blue.jpg +0 -0
  4. package/assets/spark/colorama-gradient-map-green.jpg +0 -0
  5. package/assets/spark/ray-pulse.mp4 +0 -0
  6. package/assets/spark/spark-base-video.mp4 +0 -0
  7. package/assets/spark/success-animation-circle.mp4 +0 -0
  8. package/build/lib/native/components/Spark/RazorSenseGradient/FluidGradient.js +9 -0
  9. package/build/lib/native/components/Spark/RazorSenseGradient/FluidGradient.js.map +1 -0
  10. package/build/lib/native/components/Spark/RazorSenseGradient/FluidGradientMount.js +18 -0
  11. package/build/lib/native/components/Spark/RazorSenseGradient/FluidGradientMount.js.map +1 -0
  12. package/build/lib/native/components/Spark/RazorSenseGradient/shader.js +69 -0
  13. package/build/lib/native/components/Spark/RazorSenseGradient/shader.js.map +1 -0
  14. package/build/lib/native/components/Spark/RazorSenseGradient/useFluidGradient.js +7 -0
  15. package/build/lib/native/components/Spark/RazorSenseGradient/useFluidGradient.js.map +1 -0
  16. package/build/lib/native/components/Spark/RzpGlass/PerformanceManager.js +7 -0
  17. package/build/lib/native/components/Spark/RzpGlass/PerformanceManager.js.map +1 -0
  18. package/build/lib/native/components/Spark/RzpGlass/RzpGlass.js +13 -0
  19. package/build/lib/native/components/Spark/RzpGlass/RzpGlass.js.map +1 -0
  20. package/build/lib/native/components/Spark/RzpGlass/RzpGlassMount.js +28 -0
  21. package/build/lib/native/components/Spark/RzpGlass/RzpGlassMount.js.map +1 -0
  22. package/build/lib/native/components/Spark/RzpGlass/presets.js +4 -0
  23. package/build/lib/native/components/Spark/RzpGlass/presets.js.map +1 -0
  24. package/build/lib/native/components/Spark/RzpGlass/rzpGlassShader.js +920 -0
  25. package/build/lib/native/components/Spark/RzpGlass/rzpGlassShader.js.map +1 -0
  26. package/build/lib/native/components/Spark/RzpGlass/utils.js +4 -0
  27. package/build/lib/native/components/Spark/RzpGlass/utils.js.map +1 -0
  28. package/build/lib/native/components/Spark/RzpGlass/webgl-utils.js +7 -0
  29. package/build/lib/native/components/Spark/RzpGlass/webgl-utils.js.map +1 -0
  30. package/build/lib/native/components/index.js +2 -0
  31. package/build/lib/native/components/index.js.map +1 -1
  32. package/build/lib/web/development/_virtual/flatten.js +1 -1
  33. package/build/lib/web/development/_virtual/flatten3.js +1 -1
  34. package/build/lib/web/development/components/Dropdown/FilterChipSelectInput.web.js +23 -15
  35. package/build/lib/web/development/components/Dropdown/FilterChipSelectInput.web.js.map +1 -1
  36. package/build/lib/web/development/components/SideNav/SideNav.web.js +21 -21
  37. package/build/lib/web/development/components/SideNav/SideNav.web.js.map +1 -1
  38. package/build/lib/web/development/components/SideNav/SideNavItems/SideNavLink.web.js +4 -4
  39. package/build/lib/web/development/components/SideNav/SideNavItems/SideNavLink.web.js.map +1 -1
  40. package/build/lib/web/development/components/Spark/RazorSenseGradient/FluidGradient.js +92 -0
  41. package/build/lib/web/development/components/Spark/RazorSenseGradient/FluidGradient.js.map +1 -0
  42. package/build/lib/web/development/components/Spark/RazorSenseGradient/FluidGradientMount.js +110 -0
  43. package/build/lib/web/development/components/Spark/RazorSenseGradient/FluidGradientMount.js.map +1 -0
  44. package/build/lib/web/development/components/Spark/RazorSenseGradient/index.js +2 -0
  45. package/build/lib/web/development/components/Spark/RazorSenseGradient/index.js.map +1 -0
  46. package/build/lib/web/development/components/Spark/RazorSenseGradient/shader.js +18 -0
  47. package/build/lib/web/development/components/Spark/RazorSenseGradient/shader.js.map +1 -0
  48. package/build/lib/web/development/components/Spark/RazorSenseGradient/useFluidGradient.js +34 -0
  49. package/build/lib/web/development/components/Spark/RazorSenseGradient/useFluidGradient.js.map +1 -0
  50. package/build/lib/web/development/components/Spark/RzpGlass/PerformanceManager.js +455 -0
  51. package/build/lib/web/development/components/Spark/RzpGlass/PerformanceManager.js.map +1 -0
  52. package/build/lib/web/development/components/Spark/RzpGlass/RzpGlass.js +263 -0
  53. package/build/lib/web/development/components/Spark/RzpGlass/RzpGlass.js.map +1 -0
  54. package/build/lib/web/development/components/Spark/RzpGlass/RzpGlassMount.js +908 -0
  55. package/build/lib/web/development/components/Spark/RzpGlass/RzpGlassMount.js.map +1 -0
  56. package/build/lib/web/development/components/Spark/RzpGlass/index.js +24 -0
  57. package/build/lib/web/development/components/Spark/RzpGlass/index.js.map +1 -0
  58. package/build/lib/web/development/components/Spark/RzpGlass/presets.js +151 -0
  59. package/build/lib/web/development/components/Spark/RzpGlass/presets.js.map +1 -0
  60. package/build/lib/web/development/components/Spark/RzpGlass/rzpGlassShader.js +5 -0
  61. package/build/lib/web/development/components/Spark/RzpGlass/rzpGlassShader.js.map +1 -0
  62. package/build/lib/web/development/components/Spark/RzpGlass/utils.js +77 -0
  63. package/build/lib/web/development/components/Spark/RzpGlass/utils.js.map +1 -0
  64. package/build/lib/web/development/components/Spark/RzpGlass/webgl-utils.js +200 -0
  65. package/build/lib/web/development/components/Spark/RzpGlass/webgl-utils.js.map +1 -0
  66. package/build/lib/web/development/components/Spark/index.js +3 -0
  67. package/build/lib/web/development/components/Spark/index.js.map +1 -0
  68. package/build/lib/web/development/components/index.js +3 -0
  69. package/build/lib/web/development/components/index.js.map +1 -1
  70. package/build/lib/web/development/node_modules/es-toolkit/dist/array/flatten.js +1 -1
  71. package/build/lib/web/development/node_modules/es-toolkit/dist/compat/array/flatten.js +1 -1
  72. package/build/lib/web/development/node_modules/es-toolkit/dist/compat/array/sortBy.js +2 -2
  73. package/build/lib/web/development/node_modules/es-toolkit/dist/compat/object/omit.js +2 -2
  74. package/build/lib/web/production/components/Dropdown/FilterChipSelectInput.web.js +23 -15
  75. package/build/lib/web/production/components/Dropdown/FilterChipSelectInput.web.js.map +1 -1
  76. package/build/lib/web/production/components/SideNav/SideNav.web.js +21 -21
  77. package/build/lib/web/production/components/SideNav/SideNav.web.js.map +1 -1
  78. package/build/lib/web/production/components/SideNav/SideNavItems/SideNavLink.web.js +4 -4
  79. package/build/lib/web/production/components/SideNav/SideNavItems/SideNavLink.web.js.map +1 -1
  80. package/build/lib/web/production/components/Spark/RazorSenseGradient/FluidGradient.js +92 -0
  81. package/build/lib/web/production/components/Spark/RazorSenseGradient/FluidGradient.js.map +1 -0
  82. package/build/lib/web/production/components/Spark/RazorSenseGradient/FluidGradientMount.js +110 -0
  83. package/build/lib/web/production/components/Spark/RazorSenseGradient/FluidGradientMount.js.map +1 -0
  84. package/build/lib/web/production/components/Spark/RazorSenseGradient/index.js +2 -0
  85. package/build/lib/web/production/components/Spark/RazorSenseGradient/index.js.map +1 -0
  86. package/build/lib/web/production/components/Spark/RazorSenseGradient/shader.js +18 -0
  87. package/build/lib/web/production/components/Spark/RazorSenseGradient/shader.js.map +1 -0
  88. package/build/lib/web/production/components/Spark/RazorSenseGradient/useFluidGradient.js +34 -0
  89. package/build/lib/web/production/components/Spark/RazorSenseGradient/useFluidGradient.js.map +1 -0
  90. package/build/lib/web/production/components/Spark/RzpGlass/PerformanceManager.js +455 -0
  91. package/build/lib/web/production/components/Spark/RzpGlass/PerformanceManager.js.map +1 -0
  92. package/build/lib/web/production/components/Spark/RzpGlass/RzpGlass.js +263 -0
  93. package/build/lib/web/production/components/Spark/RzpGlass/RzpGlass.js.map +1 -0
  94. package/build/lib/web/production/components/Spark/RzpGlass/RzpGlassMount.js +908 -0
  95. package/build/lib/web/production/components/Spark/RzpGlass/RzpGlassMount.js.map +1 -0
  96. package/build/lib/web/production/components/Spark/RzpGlass/index.js +24 -0
  97. package/build/lib/web/production/components/Spark/RzpGlass/index.js.map +1 -0
  98. package/build/lib/web/production/components/Spark/RzpGlass/presets.js +151 -0
  99. package/build/lib/web/production/components/Spark/RzpGlass/presets.js.map +1 -0
  100. package/build/lib/web/production/components/Spark/RzpGlass/rzpGlassShader.js +5 -0
  101. package/build/lib/web/production/components/Spark/RzpGlass/rzpGlassShader.js.map +1 -0
  102. package/build/lib/web/production/components/Spark/RzpGlass/utils.js +77 -0
  103. package/build/lib/web/production/components/Spark/RzpGlass/utils.js.map +1 -0
  104. package/build/lib/web/production/components/Spark/RzpGlass/webgl-utils.js +200 -0
  105. package/build/lib/web/production/components/Spark/RzpGlass/webgl-utils.js.map +1 -0
  106. package/build/lib/web/production/components/Spark/index.js +3 -0
  107. package/build/lib/web/production/components/Spark/index.js.map +1 -0
  108. package/build/lib/web/production/components/index.js +3 -0
  109. package/build/lib/web/production/components/index.js.map +1 -1
  110. package/build/types/components/index.d.ts +297 -1
  111. package/build/types/components/index.native.d.ts +297 -1
  112. package/package.json +2 -1
@@ -0,0 +1,920 @@
1
+ var rzpGlassVertexShader=`
2
+ precision mediump float;
3
+
4
+ attribute vec2 position;
5
+ attribute vec2 uv;
6
+
7
+ // Zoom & Pan uniforms (computed in vertex shader for efficiency)
8
+ uniform float uZoom;
9
+ uniform vec2 uPan; // vec2(uPanX, uPanY)
10
+
11
+ // Output varyings
12
+ varying vec2 vUv; // Raw screen UV (for screen-space effects like feathering)
13
+ varying vec2 vContentUv; // Transformed UV for video/content sampling (zoom + pan applied)
14
+
15
+ void main() {
16
+ // Raw screen UV for screen-space effects
17
+ vUv = uv;
18
+
19
+ // Compute zoomed/panned UV for content sampling
20
+ // Zoom: scale around center (0.5, 0.5)
21
+ // Pan: offset the view
22
+ vContentUv = (uv - 0.5) / uZoom + 0.5;
23
+ vContentUv += uPan;
24
+
25
+ gl_Position = vec4(position, 0, 1);
26
+ }
27
+ `;var rzpGlassFragmentShader=`
28
+ precision mediump float;
29
+
30
+ uniform float uTime;
31
+ uniform vec2 iResolution;
32
+ uniform float uDpr;
33
+ uniform sampler2D uVideoTexture;
34
+ uniform sampler2D uGradientMap;
35
+ uniform sampler2D uGradientMap2; // Second gradient map for cross-fade blending
36
+ uniform sampler2D uCenterGradientMap; // Separate gradient map for center ellipse
37
+
38
+ // Layer toggles (enable/disable actual effects)
39
+ uniform float uEnableDisplacement;
40
+ uniform float uEnableColorama;
41
+ uniform float uEnableBloom;
42
+ uniform float uEnableLightSweep;
43
+
44
+ // ============================================
45
+ // COLORAMA UNIFORMS (Adobe AE v5 Pipeline)
46
+ // Pipeline: Scalar → Remap → Warp → Wrap → Lookup → Blend
47
+ // ============================================
48
+
49
+ // --- 1. INPUT PHASE (Scalar Index Generation) ---
50
+ uniform float uInputMin; // Input range min (default 0.0)
51
+ uniform float uInputMax; // Input range max (default 1.0)
52
+
53
+ // --- 2. MODIFY PHASE (Index Space Warping) ---
54
+ uniform float uModifyGamma; // Gamma curve: <1 = brights, >1 = darks (default 1.0)
55
+ uniform float uPosterizeLevels; // 0 = off, >0 = number of discrete steps
56
+ uniform float uCycleRepetitions; // Stretch/compress the index (default 1.0)
57
+ uniform float uPhaseShift; // Static offset (default 0.0)
58
+ uniform float uCycleSpeed; // Cycling animation speed (default 0.0)
59
+
60
+ // --- 3. OUTPUT CYCLE (Wrap & Lookup) ---
61
+ uniform float uWrapMode; // 0 = clamp, 1 = wrap/fract (default 1.0)
62
+ uniform float uReverse; // 0 = normal, 1 = reverse gradient (default 0.0)
63
+
64
+ // --- 4. COMPOSITE ---
65
+ uniform float uBlendWithOriginal; // 0 = full effect, 1 = original (default 0.0)
66
+ uniform float uGradientMapBlend; // 0 = uGradientMap, 1 = uGradientMap2 (default 0.0)
67
+
68
+ // --- 5. LIGHT EFFECT ---
69
+ uniform float uLightIntensity; // Strength of light sweep effect
70
+ uniform float uFrameCount; // Current frame number
71
+ uniform float uLightStartFrame; // Frame when light effect starts
72
+
73
+ // --- 6. DISPLACEMENT ---
74
+ uniform float uNumSegments; // Number of glass slits (default 45.0)
75
+ uniform float uSlitAngle; // Angle of slits in radians (default 0.13)
76
+ uniform float uDisplacementX; // X displacement amount (default -12.0)
77
+ uniform float uDisplacementY; // Y displacement amount (default -20.0)
78
+
79
+ // --- 7. CENTER ELEMENT ---
80
+ uniform float uEnableCenterElement; // Toggle center element (0 = off, 1 = on)
81
+ uniform float uCenterAnimDuration; // Duration of one animation cycle in seconds
82
+ uniform float uCenterAnimTime; // Current animation time in seconds (resets with video loop)
83
+
84
+ // --- 8. COLOR CORRECTION ---
85
+ uniform float uCCBlackPoint; // Levels black point (default 0.0)
86
+ uniform float uCCWhitePoint; // Levels white point (default 1.0)
87
+ uniform float uCCMidtoneGamma; // Midtone gamma (default 1.2)
88
+ uniform float uCCGamma; // Output gamma (default 1.2)
89
+ uniform float uCCContrast; // Contrast boost (default 0.0)
90
+
91
+ // --- 9. ZOOM & PAN ---
92
+ uniform float uZoom; // Zoom level (1.0 = normal, 2.0 = 2x zoom) - still needed for edge feather check
93
+ uniform vec4 uEdgeFeather; // Per-side feathering: vec4(top, right, bottom, left) clockwise, 0 = none, 1 = max
94
+ uniform vec2 uRefResolution; // Reference resolution for zoom-independent displacement
95
+ uniform vec4 uVisibleUvBounds; // vec4(minX, minY, maxX, maxY) - visible portion of canvas in container
96
+
97
+ // --- 10. BACKGROUND COLOR ---
98
+ uniform vec3 uBackgroundColor; // Background color to blend with (RGB 0-1)
99
+
100
+ // UV coordinates from the vertex shader
101
+ varying vec2 vUv; // Raw screen UV (for screen-space effects)
102
+ varying vec2 vContentUv; // Transformed UV with zoom/pan applied (for content sampling)
103
+
104
+ // ============================================
105
+ // UTILITY FUNCTIONS
106
+ // ============================================
107
+ // Rec. 709 luminance calculation
108
+ float luminance(vec3 color) {
109
+ return dot(color, vec3(0.2126, 0.7152, 0.0722));
110
+ }
111
+
112
+ // ============================================
113
+ // COLORAMA EFFECT (Adobe After Effects v5 Pipeline)
114
+ // ============================================
115
+ //
116
+ // Pipeline:
117
+ // Image → Scalar Field (0-1) → Warp/Animate → Gradient Lookup → Composite
118
+ //
119
+ // This matches AE's indexed gradient remapping with time-domain cycling.
120
+ vec3 applyColoramaWithGradient(
121
+ sampler2D gradientMap, // Gradient map texture to sample from
122
+ float rawIntensity, // Raw luminance from pixel
123
+ float inputMin, // Input range min
124
+ float inputMax, // Input range max
125
+ float gamma, // Gamma curve (pow)
126
+ float posterizeLevels, // 0 = off, else discrete steps
127
+ float cycleReps, // Cycle repetitions (stretch)
128
+ float phaseShift, // Static offset
129
+ float cycleSpeed, // Time-based cycling
130
+ float wrapMode, // 0 = clamp, 1 = wrap
131
+ float reverse // 0 = normal, 1 = flip
132
+ ) {
133
+ // ─────────────────────────────────────────────
134
+ // STEP 1: INPUT PHASE - Scalar Index Generation
135
+ // ─────────────────────────────────────────────
136
+ // Normalize intensity to input range
137
+ float t = clamp((rawIntensity - inputMin) / (inputMax - inputMin), 0.0, 1.0);
138
+
139
+ // ─────────────────────────────────────────────
140
+ // STEP 2: MODIFY PHASE - Index Space Warping
141
+ // ─────────────────────────────────────────────
142
+
143
+ // a) Gamma / Curves - reshape the intensity distribution
144
+ t = pow(t, gamma);
145
+
146
+ // b) Posterize - quantize to discrete levels (branchless)
147
+ // When posterizeLevels <= 0, keeps t unchanged
148
+ float posterized = floor(t * posterizeLevels + 0.0001) / max(posterizeLevels, 0.0001);
149
+ t = mix(t, posterized, step(0.001, posterizeLevels));
150
+
151
+ // c) Cycle Repetitions - stretch/compress across gradient
152
+ t = t * cycleReps;
153
+
154
+ // d) Phase Shift - static offset
155
+ t = t + phaseShift;
156
+
157
+ // e) Cycling Animation - time-based offset
158
+ t = t + cycleSpeed * uTime;
159
+
160
+ // ─────────────────────────────────────────────
161
+ // STEP 3: OUTPUT CYCLE - Wrap & Lookup (branchless)
162
+ // ─────────────────────────────────────────────
163
+
164
+ // Wrap (fract) vs Clamp - branchless selection
165
+ t = mix(clamp(t, 0.0, 1.0), fract(t), step(0.5, wrapMode));
166
+
167
+ // Reverse direction - branchless
168
+ t = mix(t, 1.0 - t, step(0.5, reverse));
169
+
170
+ // Gradient lookup (1D texture sample)
171
+ return texture2D(gradientMap, vec2(t, 0.5)).rgb;
172
+ }
173
+
174
+ // ============================================
175
+ // DISPLACEMENT FUNCTIONS
176
+ // ============================================
177
+ // Create striped displacement map for glass refraction effect
178
+ // Returns: x = signed displacement (-1 to 1), y = local UV x position within segment
179
+ // gradientStart: gradient value at left edge (typically 1.0 for white)
180
+ // gradientEnd: gradient value at right edge (typically 0.0 for black)
181
+ // gradientPower: power curve for falloff (1.0 = linear, <1.0 = steeper, >1.0 = gentler)
182
+ // centerPoint: center value for signed conversion (typically 0.5)
183
+ // aspect: screen aspect ratio (width/height) for consistent slit angle
184
+ vec2 createStripedDisplacement(
185
+ vec2 uv,
186
+ float numSegments,
187
+ float angle,
188
+ float gradientStart,
189
+ float gradientEnd,
190
+ float gradientPower,
191
+ float centerPoint,
192
+ float aspect
193
+ ) {
194
+ // Work in aspect-corrected UV space where x and y have equal visual scale
195
+ // This ensures consistent slit angle regardless of viewport dimensions
196
+ vec2 aspectUV = uv * vec2(aspect, 1.0);
197
+
198
+ // Apply slant in aspect-corrected space
199
+ float slantedX = aspectUV.x - aspectUV.y * tan(angle);
200
+
201
+ // Calculate segment properties (account for aspect-scaled x range)
202
+ float segmentWidth = aspect / numSegments;
203
+ float localUVx = fract(slantedX / segmentWidth); // 0-1 within each segment
204
+
205
+ // Create the displacement map gradient
206
+ // Use smoothstep for smoother interpolation
207
+ float smoothUVx = smoothstep(0.0, 1.0, localUVx);
208
+ // Interpolate from gradientEnd (left) to gradientStart (right)
209
+ float rawGradient = mix(gradientEnd, gradientStart, smoothUVx);
210
+
211
+ // Apply power curve for falloff control
212
+ rawGradient = pow(rawGradient, gradientPower);
213
+
214
+ // Convert to signed displacement (-1 to 1) using centerPoint
215
+ // centerPoint is the neutral value (typically 0.5)
216
+ float signedDisplacement = (rawGradient - centerPoint) / centerPoint;
217
+
218
+ return vec2(signedDisplacement, localUVx);
219
+ }
220
+
221
+ // Apply displacement offset to UV coordinates
222
+ vec2 applyDisplacement(vec2 uv, float signedDisplacement, vec2 maxDisplacement, vec2 resolution) {
223
+ vec2 displaceOffset = vec2(
224
+ signedDisplacement * maxDisplacement.x / resolution.x,
225
+ signedDisplacement * maxDisplacement.y / resolution.y
226
+ );
227
+ return uv + displaceOffset;
228
+ }
229
+
230
+ // Create thin slanted stripes with multi-stop gradient color
231
+ // Returns RGB color: gradient stripes with 3 color stops
232
+ // Stop 1 (0%): colorStart, Stop 2 (stopPosition): colorMid, Stop 3 (100%): transparent
233
+ vec4 createStripes(
234
+ vec2 uv,
235
+ float numSegments,
236
+ float angle,
237
+ float stopPosition, // Position of middle stop (0.0 to 1.0)
238
+ vec4 colorStart, // Color at 0% (left edge)
239
+ vec4 colorMid, // Color at stopPosition
240
+ float aspect // Screen aspect ratio for consistent angle
241
+ ) {
242
+ // Work in aspect-corrected UV space where x and y have equal visual scale
243
+ vec2 aspectUV = uv * vec2(aspect, 1.0);
244
+
245
+ // Apply slant in aspect-corrected space
246
+ float slantedX = aspectUV.x - aspectUV.y * tan(angle);
247
+
248
+ // Calculate segment properties (account for aspect-scaled x range)
249
+ float segmentWidth = aspect / numSegments;
250
+ float localUVx = 1.0 - fract(slantedX / segmentWidth); // 0-1 within each segment, reversed
251
+
252
+ // Multi-stop gradient:
253
+ // 0% -> colorStart (green)
254
+ // stopPosition -> colorMid (white)
255
+ // 100% -> transparent (black with 0 opacity)
256
+
257
+ vec4 gradientColor;
258
+ float opacity;
259
+
260
+ if (localUVx < stopPosition) {
261
+ float t = localUVx / stopPosition;
262
+ gradientColor = mix(colorMid, colorStart, t);
263
+ opacity = 0.5;
264
+ } else {
265
+ float t = (localUVx - stopPosition) / (1.0 - stopPosition);
266
+ gradientColor = mix(vec4(0.0), colorMid, t);
267
+ opacity = 0.5 - t * 0.5;
268
+ }
269
+
270
+ return gradientColor * opacity;
271
+ }
272
+
273
+ // Sample texture with displacement applied
274
+ vec4 sampleWithDisplacement(
275
+ sampler2D tex,
276
+ vec2 uv,
277
+ float signedDisplacement,
278
+ vec2 maxDisplacement,
279
+ vec2 resolution
280
+ ) {
281
+ vec2 displacedUV = applyDisplacement(uv, signedDisplacement, maxDisplacement, resolution);
282
+ return texture2D(tex, displacedUV);
283
+ }
284
+
285
+ // ============================================
286
+ // POST-PROCESSING EFFECTS
287
+ // ============================================
288
+ vec3 applyBloom(vec3 color, float intensity, float innerMask) {
289
+ const float whiteCoreThresholdMin = 0.5; // Start of white core mask
290
+ const float whiteCoreThresholdMax = 0.85; // End of white core mask
291
+ const float whiteCoreBlendStrength = 0.85; // How much to blend towards pure white
292
+
293
+ const float bloomThresholdMin = 0.3; // Start of bloom glow
294
+ const float bloomThresholdMax = 0.7; // End of bloom glow
295
+ const vec3 bloomColor = vec3(1.0, 0.99, 0.97); // Warm white bloom tint
296
+ const float bloomStrength = 0.10; // Intensity of bloom glow
297
+ // -------------------------------
298
+
299
+ // Calculate how much we're in the "center" bright area
300
+ // Use a tighter threshold for the white core
301
+ float whiteCoreMask = smoothstep(whiteCoreThresholdMin, whiteCoreThresholdMax, intensity) * innerMask;
302
+
303
+ // Pure white target
304
+ vec3 pureWhite = vec3(1.0);
305
+
306
+ // Blend the center towards pure white (not additive, but replacement blend)
307
+ // This ensures the very center goes to white, not gray
308
+ color = mix(color, pureWhite, whiteCoreMask * whiteCoreBlendStrength);
309
+
310
+ // Additional soft bloom glow around the white core
311
+ float bloomBase = smoothstep(bloomThresholdMin, bloomThresholdMax, intensity);
312
+ float bloomAmount = bloomBase * innerMask;
313
+ color += bloomColor * bloomAmount * bloomStrength;
314
+
315
+ return color;
316
+ }
317
+
318
+ // ============================================
319
+ // ANIMATED POLYGON SHAPE
320
+ // ============================================
321
+ // Struct to return shape data
322
+ struct ShapeData {
323
+ float shape; // The shape value (0 = outside, 1 = center)
324
+ float gradient; // Gradient from gray (edge) to white (center)
325
+ };
326
+
327
+ // Signed distance function for a regular polygon
328
+ // p: point to test, r: radius, n: number of sides
329
+ float sdPolygon(vec2 p, float r, float n) {
330
+ // Angle and radius
331
+ float an = 3.141593 / n;
332
+ vec2 acs = vec2(cos(an), sin(an));
333
+
334
+ // Reduce to first sector
335
+ float bn = mod(atan(p.x, p.y), 2.0 * an) - an;
336
+ p = length(p) * vec2(cos(bn), abs(sin(bn)));
337
+
338
+ // Line sdf
339
+ p -= r * acs;
340
+ p.y += clamp(-p.y, 0.0, r * acs.y);
341
+
342
+ return length(p) * sign(p.x);
343
+ }
344
+
345
+ // Fast signed distance function for an ellipse
346
+ // Approximation that avoids expensive acos(), cube roots, and branching
347
+ // Accurate enough for visual effects, ~5x faster than exact version
348
+ float sdEllipse(vec2 p, vec2 ab) {
349
+ // Normalize point by ellipse radii
350
+ vec2 q = p / ab;
351
+ float k1 = length(q);
352
+
353
+ // Early out for points very close to center (avoid division issues)
354
+ if (k1 < 0.0001) return -min(ab.x, ab.y);
355
+
356
+ // Gradient-based distance approximation
357
+ vec2 q2 = q / ab; // Second normalization for gradient
358
+ float k2 = length(q2);
359
+
360
+ return k1 * (k1 - 1.0) / k2;
361
+ }
362
+
363
+ // Helper: Calculate a single shape instance at a given animation phase
364
+ ShapeData calculateSingleShape(
365
+ vec2 uv,
366
+ float linearT, // Animation phase 0-1
367
+ float solidCoreMask,
368
+ vec2 resolution,
369
+ // Shape parameters
370
+ float shapeType,
371
+ float shapeWidth,
372
+ float shapeHeight,
373
+ float centerY,
374
+ float animRange,
375
+ float edgeSoftness,
376
+ float grayLevel,
377
+ float shapeAngleStart,
378
+ float shapeAngleEnd,
379
+ float shapeSize
380
+ ) {
381
+ // Map 0-1 to position range (left to right)
382
+ float posOffset = (linearT * 2.0 - 1.0) * animRange;
383
+ float centerX = 0.5 + posOffset;
384
+
385
+ // Animate rotation
386
+ float animatedAngle = mix(shapeAngleStart, shapeAngleEnd, linearT);
387
+
388
+ // Correct for aspect ratio
389
+ float aspect = resolution.x / resolution.y;
390
+
391
+ // Calculate position relative to center
392
+ vec2 shapeCenter = vec2(centerX, centerY);
393
+ vec2 delta = uv - shapeCenter;
394
+
395
+ // Rotate delta by animated angle FIRST
396
+ float cosA = cos(animatedAngle);
397
+ float sinA = sin(animatedAngle);
398
+ vec2 rotatedDelta = vec2(
399
+ delta.x * cosA - delta.y * sinA,
400
+ delta.x * sinA + delta.y * cosA
401
+ );
402
+
403
+ // Apply aspect correction AFTER rotation
404
+ rotatedDelta.x *= aspect;
405
+
406
+ // Calculate distance based on shape type
407
+ float dist;
408
+ if (shapeType < 0.5) {
409
+ dist = sdEllipse(rotatedDelta, vec2(shapeWidth, shapeHeight));
410
+ } else {
411
+ vec2 scaledDelta = rotatedDelta / vec2(shapeWidth, shapeHeight);
412
+ dist = sdPolygon(scaledDelta, shapeSize / min(shapeWidth, shapeHeight), shapeType);
413
+ dist *= min(shapeWidth, shapeHeight);
414
+ }
415
+
416
+ // Normalize distance for gradient
417
+ float normalizedDist;
418
+ if (shapeType < 0.5) {
419
+ normalizedDist = dist / max(shapeWidth, shapeHeight) + 1.0;
420
+ } else {
421
+ normalizedDist = (dist / shapeSize) + 1.0;
422
+ }
423
+ normalizedDist = clamp(normalizedDist, 0.0, 1.0);
424
+
425
+ // Create soft shape mask
426
+ float shapeMask = 1.0 - smoothstep(-edgeSoftness * 0.1, edgeSoftness * 0.05, dist);
427
+
428
+ // Create gradient
429
+ float gradient = mix(1.0, grayLevel, smoothstep(0.0, 1.0, normalizedDist));
430
+
431
+ // Apply solid core mask
432
+ shapeMask *= solidCoreMask;
433
+
434
+ ShapeData result;
435
+ result.shape = shapeMask;
436
+ result.gradient = gradient;
437
+ return result;
438
+ }
439
+
440
+ // Creates two staggered animated shapes that move left-to-right
441
+ // When one reaches the far edge, another appears from the left
442
+ ShapeData calculateAnimatedShape(
443
+ vec2 uv,
444
+ float time, // Current animation time in seconds
445
+ float solidCoreMask,
446
+ vec2 resolution
447
+ ) {
448
+ // --- Configurable parameters ---
449
+ const float shapeType = 3.0; // 0 = ellipse, 3 = triangle, 4 = square, 5 = pentagon, etc.
450
+ const float shapeWidth = 0.1; // Width/horizontal scale (wide)
451
+ const float shapeHeight = 0.8; // Height/vertical scale (short)
452
+ const float centerY = 0.4; // Vertical center position
453
+ float cycleDuration = uCenterAnimDuration; // Seconds per animation cycle (from uniform)
454
+ const float animRange = 0.7; // How far left/right it travels
455
+ const float edgeSoftness = 0.5; // Softness of shape edge
456
+ const float grayLevel = 0.5; // Gray color at shape edge
457
+ const float shapeAngleStart = 0.6; // Rotation angle at start (slight tilt)
458
+ const float shapeAngleEnd = 0.1; // Rotation angle at end (opposite tilt)
459
+ const float shapeSize = 0.4; // Overall size for polygon mode
460
+ const float staggerOffset = 0.4; // Offset between the two shapes (0.5 = half cycle apart)
461
+ const float shape2Scale = 1.3; // Scale multiplier for 2nd shape (1.0 = same size)
462
+ // -------------------------------
463
+
464
+ // Time-based animation: time / cycleDuration gives progress through cycle
465
+ float linearT1 = fract(time / cycleDuration); // Shape 1: 0->1 repeating
466
+ float linearT2 = fract(time / cycleDuration + staggerOffset); // Shape 2: offset by staggerOffset
467
+
468
+ // Calculate both shapes (shape 2 is slightly larger)
469
+ ShapeData shape1 = calculateSingleShape(
470
+ uv, linearT1, solidCoreMask, resolution,
471
+ shapeType, shapeWidth, shapeHeight, centerY, animRange,
472
+ edgeSoftness, grayLevel, shapeAngleStart, shapeAngleEnd, shapeSize
473
+ );
474
+
475
+ ShapeData shape2 = calculateSingleShape(
476
+ uv, linearT2, solidCoreMask, resolution,
477
+ shapeType, shapeWidth * shape2Scale, shapeHeight * shape2Scale, centerY, animRange,
478
+ edgeSoftness, grayLevel, shapeAngleStart, shapeAngleEnd, shapeSize * shape2Scale
479
+ );
480
+
481
+ // Combine both shapes (take max of masks, blend gradients)
482
+ ShapeData result;
483
+ result.shape = max(shape1.shape, shape2.shape);
484
+ // Weighted average of gradients based on shape masks
485
+ float totalMask = shape1.shape + shape2.shape;
486
+ if (totalMask > 0.001) {
487
+ result.gradient = (shape1.gradient * shape1.shape + shape2.gradient * shape2.shape) / totalMask;
488
+ } else {
489
+ result.gradient = 0.5;
490
+ }
491
+
492
+ return result;
493
+ }
494
+
495
+ // Apply shape effect to intensity (for colorama/displacement pipeline)
496
+ float applyShapeToIntensity(
497
+ float baseIntensity,
498
+ ShapeData shapeData,
499
+ float effectStrength
500
+ ) {
501
+ // Blend the shape gradient into the base intensity
502
+ // This makes the shape area brighter/differently colored through colorama
503
+ float shapeContribution = shapeData.gradient * shapeData.shape;
504
+ return mix(baseIntensity, shapeContribution, shapeData.shape * effectStrength);
505
+ }
506
+
507
+
508
+ // AE-style color processing (levels, gamma, contrast). Used in both ripple and normal mode.
509
+ vec3 applyColorCorrection(vec3 color) {
510
+ color = (color - uCCBlackPoint) / (uCCWhitePoint - uCCBlackPoint);
511
+ color = pow(max(color, vec3(0.0)), vec3(1.0 / (uCCMidtoneGamma * uCCGamma)));
512
+ color = color * (1.0 + uCCContrast) - uCCContrast * 0.5;
513
+ return clamp(color, 0.0, 1.0);
514
+ }
515
+
516
+ // Feather at container edges (visible bounds). Used in both ripple and normal mode.
517
+ vec3 applyEdgeFeathering(vec3 color) {
518
+ // Apply edge feathering when zoomed in
519
+ // Feathering is applied at the container edges (visible bounds), not canvas edges
520
+ // uEdgeFeather = vec4(top, right, bottom, left) — clockwise like CSS
521
+ if (any(greaterThan(uEdgeFeather, vec4(0.0)))) {
522
+ vec2 screenUV = vUv;
523
+
524
+ // Get visible UV bounds (where container clips the canvas)
525
+ float visMinX = uVisibleUvBounds.x;
526
+ float visMinY = uVisibleUvBounds.y;
527
+ float visMaxX = uVisibleUvBounds.z;
528
+ float visMaxY = uVisibleUvBounds.w;
529
+
530
+ // Calculate visible dimensions in UV space for aspect-correct feathering on X axis
531
+ float visibleWidth = visMaxX - visMinX;
532
+ float visibleHeight = visMaxY - visMinY;
533
+ float visibleAspect = visibleWidth / visibleHeight;
534
+
535
+ // Per-side feather amounts (X sides get aspect correction for pixel-equal width)
536
+ float featherTop = uEdgeFeather.x * 0.15 / visibleAspect;
537
+ float featherRight = uEdgeFeather.y * 0.15 / visibleAspect;
538
+ float featherBottom = uEdgeFeather.z * 0.15 / visibleAspect;
539
+ float featherLeft = uEdgeFeather.w * 0.15 / visibleAspect;
540
+
541
+ // Apply feathering at container edges (visible bounds)
542
+ float left = smoothstep(visMinX, visMinX + featherLeft, screenUV.x);
543
+ float right = smoothstep(visMaxX, visMaxX - featherRight, screenUV.x);
544
+ float bottom = smoothstep(visMinY, visMinY + featherBottom, screenUV.y);
545
+ float top = smoothstep(visMaxY, visMaxY - featherTop, screenUV.y);
546
+
547
+ float edgeMask = left * right * bottom * top;
548
+ color = mix(vec3(1.0), color, edgeMask);
549
+ }
550
+ return color;
551
+ }
552
+
553
+ void main() {
554
+ // ============================================
555
+ // LAYER 1: Base glass effect (fine slits, whole image)
556
+ // ============================================
557
+ float numSegments = uNumSegments;
558
+ float angle = uSlitAngle;
559
+ const float blurRadius = 9.0;
560
+ const float sigma = 4.0;
561
+
562
+ // Calculate aspect ratio for consistent slit angles
563
+ float aspect = iResolution.x / iResolution.y;
564
+
565
+ // Displacement parameters (in pixels, scaled by DPR)
566
+ // Scale displacement by reference resolution ratio to maintain consistency across browser zoom levels
567
+ float resolutionScale = iResolution.x / uRefResolution.x;
568
+ vec2 maxDisplacement = vec2(uDisplacementX, uDisplacementY) * uDpr * resolutionScale;
569
+
570
+ // Use pre-computed UV from vertex shader (zoom + pan already applied)
571
+ vec2 uv = vContentUv;
572
+
573
+ // Base displacement (fine slits)
574
+ // Use raw screen UV (vUv) so slit positions stay fixed on screen regardless of pan/zoom
575
+ float gradientStart = 1.0;
576
+ float gradientEnd = 0.0;
577
+ float gradientPower = 1.0;
578
+ float centerPoint = 0.5;
579
+ vec2 displacementData = createStripedDisplacement(
580
+ vUv,
581
+ numSegments,
582
+ angle,
583
+ gradientStart,
584
+ gradientEnd,
585
+ gradientPower,
586
+ centerPoint,
587
+ aspect
588
+ );
589
+ float signedDisplacement = displacementData.x;
590
+ float localUVx = displacementData.y;
591
+
592
+ // ============================================
593
+ // LAYER 2: Inner glass effect (larger slits, center only, STATIC)
594
+ // ============================================
595
+ // Inner segments are a divisor of outer segments for perfect alignment
596
+ // 45 / 5 = 9 segments (5x larger slits that align with outer grid)
597
+ float innerNumSegments = numSegments;
598
+ float innerAngle = angle; // Same angle as outer
599
+
600
+ // Inner slits are STATIC - use raw screen UV so slits stay fixed on screen
601
+ vec2 innerDisplacementData = createStripedDisplacement(
602
+ vUv,
603
+ innerNumSegments,
604
+ innerAngle,
605
+ gradientStart,
606
+ gradientEnd,
607
+ gradientPower,
608
+ centerPoint,
609
+ aspect
610
+ );
611
+ float innerSignedDisplacement = innerDisplacementData.x;
612
+ float innerLocalUVx = innerDisplacementData.y;
613
+
614
+ // ============================================
615
+ // COMPUTE SOLID CORE MASK EARLY (needed for light & displacement masking)
616
+ // ============================================
617
+ vec4 videoFrameSample = texture2D(uVideoTexture, uv);
618
+ float maskIntensity = luminance(videoFrameSample.rgb);
619
+ float solidCoreMask = smoothstep(0.4, 0.7, maskIntensity);
620
+
621
+ // Store original displacement for shape refraction (before masking)
622
+ float originalInnerDisplacement = innerSignedDisplacement;
623
+
624
+ // Mask inner displacement by solidCoreMask - no inner displacement in center
625
+ innerSignedDisplacement *= (1.0 - solidCoreMask);
626
+
627
+ // Inner layer displacement uses same values (scaled by resolutionScale for zoom independence)
628
+ vec2 innerMaxDisplacement = vec2(30.0, 0.0) * uDpr * resolutionScale;
629
+
630
+ // ============================================
631
+ // CENTER ELEMENT (Static Ellipse + Animated Shapes)
632
+ // ============================================
633
+ float staticEllipseMask = 0.0;
634
+ float staticEllipseGradient = 0.0;
635
+ ShapeData shapeData;
636
+ shapeData.shape = 0.0;
637
+ shapeData.gradient = 0.0;
638
+
639
+ float centerFadeInDuration = 10.0;
640
+ float centerFramesSinceStart = uFrameCount - uLightStartFrame;
641
+ float centerEffectActivation = clamp(centerFramesSinceStart / centerFadeInDuration, 0.0, 1.0);
642
+
643
+ if (uEnableCenterElement > 0.5) {
644
+ // Calculate static ellipse mask
645
+ {
646
+ const float ellipseCenterX = 0.3;
647
+ const float ellipseCenterY = -0.15;
648
+ const float ellipseWidth = 0.5;
649
+ const float ellipseHeight = 0.8;
650
+ const float ellipseAngle = 0.3;
651
+ const float ellipseSoftness = 1.0;
652
+ const float ellipseGrayLevel = 0.5;
653
+
654
+ float aspect = iResolution.x / iResolution.y;
655
+
656
+ // Use RAW UV (no displacement) for the mask calculation
657
+ vec2 delta = uv - vec2(ellipseCenterX, ellipseCenterY);
658
+
659
+ // Rotate
660
+ float cosA = cos(ellipseAngle);
661
+ float sinA = sin(ellipseAngle);
662
+ vec2 rotatedDelta = vec2(
663
+ delta.x * cosA - delta.y * sinA,
664
+ delta.x * sinA + delta.y * cosA
665
+ );
666
+ rotatedDelta.x *= aspect;
667
+
668
+ // Calculate ellipse distance
669
+ float ellipseDist = sdEllipse(rotatedDelta, vec2(ellipseWidth, ellipseHeight));
670
+
671
+ // Soft shape mask
672
+ staticEllipseMask = 1.0 - smoothstep(-ellipseSoftness * 0.1, ellipseSoftness * 0.05, ellipseDist);
673
+
674
+ // Gradient
675
+ float normalizedDist = ellipseDist / max(ellipseWidth, ellipseHeight) + 1.0;
676
+ normalizedDist = clamp(normalizedDist, 0.0, 1.0);
677
+ staticEllipseGradient = mix(1.0, ellipseGrayLevel, smoothstep(0.0, 1.0, normalizedDist));
678
+
679
+ // Apply solid core mask
680
+ staticEllipseMask *= solidCoreMask;
681
+ }
682
+
683
+ // Block displacement inside the static ellipse
684
+ originalInnerDisplacement *= (1.0 - staticEllipseMask);
685
+ innerSignedDisplacement *= (1.0 - staticEllipseMask);
686
+ signedDisplacement *= (1.0 - staticEllipseMask);
687
+
688
+
689
+
690
+ // Calculate displaced UV for shape - use inner displacement for the shape refraction
691
+ vec2 shapeDisplacedUV = applyDisplacement(uv, originalInnerDisplacement, innerMaxDisplacement, iResolution);
692
+
693
+ // Calculate animated shape using DISPLACED UVs so glass slits refract through it
694
+ shapeData = calculateAnimatedShape(
695
+ shapeDisplacedUV, // Use displaced UVs!
696
+ uCenterAnimTime, // Time-based animation in seconds (resets with video loop)
697
+ solidCoreMask,
698
+ iResolution
699
+ );
700
+
701
+ // Combine static ellipse with animated shapes
702
+ {
703
+ float combinedShape = max(shapeData.shape, staticEllipseMask) * centerEffectActivation;
704
+ float totalMask = shapeData.shape + staticEllipseMask;
705
+ float combinedGradient = shapeData.gradient;
706
+ if (totalMask > 0.001) {
707
+ combinedGradient = (shapeData.gradient * shapeData.shape + staticEllipseGradient * staticEllipseMask) / totalMask;
708
+ }
709
+ shapeData.shape = combinedShape;
710
+ shapeData.gradient = combinedGradient;
711
+ }
712
+ }
713
+
714
+ // ============================================
715
+ // INNER EFFECT ACTIVATION - starts after uLightStartFrame
716
+ // ============================================
717
+ float innerFadeInDuration = 10.0; // Slower fade-in for inner effect
718
+ float innerFramesSinceStart = uFrameCount - uLightStartFrame;
719
+ float innerEffectActivation = clamp(innerFramesSinceStart / innerFadeInDuration, 0.0, 1.0);
720
+
721
+ // Create edge mask (solidCoreMask already computed earlier for light masking)
722
+ float edgeMask = smoothstep(0.3, 0.6, maskIntensity); // Where shape starts
723
+
724
+ // Blend outer and inner slits on the edges
725
+ // Inner contribution is multiplied by activation (fades in after frame 200)
726
+ float outerContribution = 1.0 - edgeMask * 0.5 * innerEffectActivation;
727
+ float innerContribution = edgeMask * innerEffectActivation;
728
+
729
+ // Combined displacement: inner effect fades in over time
730
+ float combinedDisplacement = signedDisplacement * outerContribution +
731
+ innerSignedDisplacement * innerContribution;
732
+
733
+ // Blend max displacement smoothly
734
+ vec2 combinedMaxDisplacement = maxDisplacement * outerContribution +
735
+ innerMaxDisplacement * innerContribution;
736
+
737
+ // For the CENTER area (solidCoreMask): use 100% inner (larger) slits displacement
738
+ // For the EDGES: use the combined displacement (blended outer + inner)
739
+ // This ensures the logo center always has the larger slits
740
+ combinedDisplacement = mix(combinedDisplacement, originalInnerDisplacement, solidCoreMask);
741
+ combinedMaxDisplacement = mix(combinedMaxDisplacement, innerMaxDisplacement, solidCoreMask);
742
+
743
+ // ============================================
744
+ // LAYER 1: DISPLACEMENT (toggleable)
745
+ // ============================================
746
+ vec4 textureSample;
747
+ if (uEnableDisplacement > 0.5) {
748
+ textureSample = sampleWithDisplacement(
749
+ uVideoTexture, uv,
750
+ combinedDisplacement, combinedMaxDisplacement,
751
+ iResolution
752
+ );
753
+ } else {
754
+ // No displacement - sample directly
755
+ textureSample = texture2D(uVideoTexture, uv);
756
+ }
757
+
758
+ // Blend localUVx for highlights - also fades in with activation
759
+ float combinedLocalUVx = localUVx * outerContribution + innerLocalUVx * innerContribution;
760
+ localUVx = combinedLocalUVx;
761
+
762
+ // Store innerMask for later use (bloom, etc.) - also tied to activation
763
+ float innerMask = edgeMask * innerEffectActivation;
764
+
765
+ // Get Phase From: Intensity (Rec. 709 luminance)
766
+ float baseIntensity = luminance(textureSample.rgb);
767
+
768
+ // Boost intensity in center areas to push them more towards white
769
+ float centerWhiteBoost = 0.1;
770
+ baseIntensity = baseIntensity + innerMask * centerWhiteBoost;
771
+ baseIntensity = clamp(baseIntensity, 0.0, 1.0);
772
+
773
+ // Keep base intensity for outer colorama (using uGradientMap)
774
+ float outerIntensity = baseIntensity;
775
+
776
+ // ============================================
777
+ // CENTER GREEN STRIPES OVERLAY (before colorama)
778
+ // ============================================
779
+ float stripeFadeOutDuration = 10.0;
780
+ float stripeFramesSinceStart = uFrameCount - uLightStartFrame;
781
+ // Effect is active UNTIL uLightStartFrame, then fades out
782
+ float stripeEffectActivation = 1.0 - clamp(stripeFramesSinceStart / stripeFadeOutDuration, 0.0, 1.0);
783
+
784
+ // Animated vertical height mask - grows from 0 to full height
785
+ // Height animation: starts at center (0.5) and expands outward
786
+ float stripeHeightDelay = 15.0; // frames to wait before starting
787
+ float stripeHeightGrowDuration = 80.0; // frames to reach full height
788
+ float stripeHeightProgress = clamp((uFrameCount - stripeHeightDelay) / stripeHeightGrowDuration, 0.0, 1.0);
789
+ // Ease the progress for smoother animation
790
+ float easedHeightProgress = 1.0 - pow(1.0 - stripeHeightProgress, 2.0);
791
+
792
+ // Calculate animated bounds - expand from center (0.5) outward
793
+ float heightHalfSpan = 0.2 * easedHeightProgress; // 0.06 = half of the 0.12 total height (0.44 to 0.56)
794
+ float softEdge = 0.1 * easedHeightProgress; // Soft edge also scales with progress
795
+ float bottomEdge = 0.5 - heightHalfSpan - softEdge;
796
+ float bottomFull = 0.5 - heightHalfSpan;
797
+ float topFull = 0.5 + heightHalfSpan;
798
+ float topEdge = 0.5 + heightHalfSpan + softEdge;
799
+
800
+ // When progress is 0, force mask to 0 to avoid glitchy edge at y=0.5
801
+ float stripeHeightMask = easedHeightProgress > 0.001
802
+ ? smoothstep(bottomEdge, bottomFull, uv.y) * smoothstep(topEdge, topFull, uv.y)
803
+ : 0.0;
804
+
805
+ vec4 centerGreenSlantedLines = createStripes(
806
+ vUv + vec2(-0.0035, 0.0), // slight offset to avoid moiré
807
+ numSegments,
808
+ uSlitAngle,
809
+ 0.15, // stopPosition (20%)
810
+ vec4(20.0/255.0, 200.0/255.0, 20.0/255.0, 0.2), // colorStart (green at 0%)
811
+ vec4(0.0, 0.0, 0.0, 0.0), // colorMid (white at 20%)
812
+ aspect // aspect ratio for consistent angle
813
+ ) * solidCoreMask * stripeHeightMask;
814
+
815
+ // Overlay green stripes on center element area
816
+ float stripeOverlayMask = solidCoreMask * stripeEffectActivation;
817
+ // Modify baseIntensity/outerIntensity with stripes before colorama
818
+ vec4 stripedTexture = vec4(textureSample.rgb, 1.0) - centerGreenSlantedLines*0.7 * stripeOverlayMask;
819
+ stripedTexture = clamp(stripedTexture, 0.0, 1.0);
820
+
821
+ // Update intensity for colorama input
822
+ float stripedIntensity = luminance(stripedTexture.rgb);
823
+ outerIntensity = mix(baseIntensity, stripedIntensity, stripeOverlayMask);
824
+
825
+ // ============================================
826
+ // LAYER 2: COLORAMA (toggleable)
827
+ // ============================================
828
+ vec3 color;
829
+ if (uEnableColorama > 0.5) {
830
+ // OUTER colorama: uses base intensity, cross-fades between uGradientMap and uGradientMap2
831
+ vec3 outerColoramaResult1 = applyColoramaWithGradient(
832
+ uGradientMap, outerIntensity,
833
+ uInputMin, uInputMax, uModifyGamma, uPosterizeLevels,
834
+ uCycleRepetitions, uPhaseShift, uCycleSpeed,
835
+ uWrapMode, uReverse
836
+ );
837
+ vec3 outerColoramaResult2 = applyColoramaWithGradient(
838
+ uGradientMap2, outerIntensity,
839
+ uInputMin, uInputMax, uModifyGamma, uPosterizeLevels,
840
+ uCycleRepetitions, uPhaseShift, uCycleSpeed,
841
+ uWrapMode, uReverse
842
+ );
843
+ vec3 outerColoramaResult = mix(outerColoramaResult1, outerColoramaResult2, uGradientMapBlend);
844
+
845
+ // Start with outer colorama as base
846
+ vec3 blendedColorama = outerColoramaResult;
847
+
848
+ // CENTER colorama: only compute when inside shape (skip texture sample otherwise)
849
+ // This saves a texture lookup + specular pow() for ~90% of pixels
850
+ if (shapeData.shape > 0.001) {
851
+ vec3 centerColoramaResult = applyColoramaWithGradient(
852
+ uCenterGradientMap, shapeData.gradient,
853
+ uInputMin, uInputMax, uModifyGamma, uPosterizeLevels,
854
+ uCycleRepetitions, uPhaseShift, uCycleSpeed,
855
+ uWrapMode, uReverse
856
+ );
857
+
858
+ // Add specular highlight to center (shiny reflection effect)
859
+ float specularPower = 8.0; // Higher = tighter/smaller highlight
860
+ float specularIntensity = 1.9; // Brightness of the specular
861
+ float specular = pow(shapeData.gradient, specularPower) * specularIntensity;
862
+ centerColoramaResult += vec3(specular); // Add bright highlight
863
+
864
+ // Blend between outer and center colorama based on shape
865
+ blendedColorama = mix(outerColoramaResult, centerColoramaResult, shapeData.shape);
866
+ }
867
+
868
+ color = mix(blendedColorama, textureSample.rgb, uBlendWithOriginal);
869
+ } else {
870
+ color = textureSample.rgb;
871
+ }
872
+
873
+ // Store intensity for bloom (use the blended value)
874
+ float intensity = mix(outerIntensity, shapeData.gradient, shapeData.shape);
875
+
876
+ // ============================================
877
+ // LAYER 3: BLOOM (toggleable)
878
+ // ============================================
879
+ if (uEnableBloom > 0.5) {
880
+ color = applyBloom(color, intensity, innerMask);
881
+ }
882
+
883
+ // ============================================
884
+ // LAYER 4: SHAPE HIGHLIGHT (toggleable via light sweep toggle)
885
+ // ============================================
886
+ if (uEnableLightSweep > 0.5) {
887
+ float lightFadeInDuration = 30.0;
888
+ float framesSinceStart = uFrameCount - uLightStartFrame;
889
+ float lightActivation = clamp(framesSinceStart / lightFadeInDuration, 0.0, 1.0);
890
+
891
+ // Add subtle brightness boost at shape center
892
+ float shapeHighlight = pow(shapeData.gradient, 2.0) * shapeData.shape;
893
+ color += vec3(1.0) * shapeHighlight * 0.15 * uLightIntensity * lightActivation;
894
+ }
895
+
896
+ // Color correction and edge feathering (shared with ripple mode)
897
+ color = applyColorCorrection(color);
898
+ color = applyEdgeFeathering(color);
899
+
900
+ // Blend with background color if provided (uBackgroundColor.r < 0 means not set)
901
+ if (uBackgroundColor.r >= 0.0) {
902
+ // Calculate luminance to determine how bright the pixel is
903
+ float brightness = luminance(color);
904
+
905
+ // Blend white/bright areas with background color
906
+ // Bright areas (close to white) become the background color
907
+ float blendStart = 0.98; // Start blending at this brightness
908
+ float blendEnd = 1.0; // Fully background color at this brightness
909
+ float blendAmount = smoothstep(blendStart, blendEnd, brightness);
910
+
911
+ // Mix the shader color with background color
912
+ color = mix(color, uBackgroundColor, blendAmount);
913
+ }
914
+
915
+ gl_FragColor = vec4(color, 1.0);
916
+ }
917
+ `;
918
+
919
+ export { rzpGlassFragmentShader, rzpGlassVertexShader };
920
+ //# sourceMappingURL=rzpGlassShader.js.map