@webeach/gl-circular-progress 0.2.1 → 0.2.2
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/lib/cjs/classes/CircularProgressFire/shaders/fragment.frag.js +1 -1
- package/lib/cjs/classes/CircularProgressFire/shaders/fragment.frag.js.map +1 -1
- package/lib/cjs/classes/CircularProgressLiquid/shaders/fragment.frag.js +1 -1
- package/lib/cjs/classes/CircularProgressLiquid/shaders/fragment.frag.js.map +1 -1
- package/lib/esm/classes/CircularProgressFire/shaders/fragment.frag.js +1 -1
- package/lib/esm/classes/CircularProgressFire/shaders/fragment.frag.js.map +1 -1
- package/lib/esm/classes/CircularProgressLiquid/shaders/fragment.frag.js +1 -1
- package/lib/esm/classes/CircularProgressLiquid/shaders/fragment.frag.js.map +1 -1
- package/package.json +9 -9
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var fragmentShaderSource = "#version 300 es\nprecision
|
|
3
|
+
var fragmentShaderSource = "#version 300 es\nprecision highp float;in vec2 v_uv;out vec4 fragColor;uniform float u_time;uniform float u_progress;uniform vec2 u_resolution;uniform float u_innerRadius;uniform float u_outerRadius;uniform float u_startAngle;uniform float u_reversed;uniform sampler2D u_gradientTexture;uniform float u_intensity;\n#define PI 3.14159265359\n#define TWO_PI 6.28318530718\nvec3 permute(vec3 x){return mod(((x*34.0)+1.0)*x,289.0);}float snoise(vec2 v){const vec4 C=vec4(0.211324865405187,0.366025403784439,-0.577350269189626,0.024390243902439);vec2 i=floor(v+dot(v,C.yy));vec2 x0=v-i+dot(i,C.xx);vec2 i1;i1=(x0.x>x0.y)? vec2(1.0,0.0): vec2(0.0,1.0);vec4 x12=x0.xyxy+C.xxzz;x12.xy-=i1;i=mod(i,289.0);vec3 p=permute(permute(i.y+vec3(0.0,i1.y,1.0))+i.x+vec3(0.0,i1.x,1.0));vec3 m=max(0.5-vec3(dot(x0,x0),dot(x12.xy,x12.xy),dot(x12.zw,x12.zw)),0.0);m=m*m;m=m*m;vec3 x=2.0*fract(p*C.www)-1.0;vec3 h=abs(x)-0.5;vec3 ox=floor(x+0.5);vec3 a0=x-ox;m*=1.79284291400159-0.85373472095314*(a0*a0+h*h);vec3 g;g.x=a0.x*x0.x+h.x*x0.y;g.yz=a0.yz*x12.xz+h.yz*x12.yw;return 130.0*dot(m,g);}void main(){vec2 st=v_uv*2.0-1.0;if(u_resolution.y>0.0){st.x*=u_resolution.x/u_resolution.y;}float radius=length(st);float absAngle=atan(st.x,st.y);if(absAngle<0.0)absAngle+=TWO_PI;float relAngle=absAngle-u_startAngle;relAngle=mod(relAngle,TWO_PI);if(relAngle<0.0)relAngle+=TWO_PI;if(u_reversed>0.5){relAngle=TWO_PI-relAngle;}float angle=mod(relAngle,TWO_PI);float progressAngle=u_progress*TWO_PI;float time=u_time*2.0;float noiseFreq=2.0;float radiusFreq=3.0;float trackWidth=u_outerRadius-u_innerRadius;float normRadius=(radius-u_innerRadius)/trackWidth;vec2 polarUV=vec2(cos(angle),sin(angle))*(2.0+normRadius)-vec2(time,time*0.5);float n=snoise(polarUV*1.5);vec2 polarUV2=vec2(cos(angle+1.0),sin(angle+1.0))*(3.0+normRadius*2.0)-vec2(time*1.5,-time);float n2=snoise(polarUV2*2.0);float fireNoise=n*0.6+n2*0.4;float aa=max(2.0/u_resolution.y,0.002);float ringInner=smoothstep(u_innerRadius-aa,u_innerRadius,radius);float trackCenter=(u_innerRadius+u_outerRadius)*0.5;float halfWidth=(u_outerRadius-u_innerRadius)*0.5;float capRadius=halfWidth;float roundingFactor=1.0;if(u_progress>0.9){roundingFactor=(1.0-u_progress)*10.0;}float effectiveCapRadius=capRadius*roundingFactor;float dEnd=(progressAngle-angle)*trackCenter;float dStart=angle*trackCenter;float dSide=halfWidth-abs(radius-trackCenter);float headRounding=1.0;if(dEnd<effectiveCapRadius&&dSide<effectiveCapRadius){float cx=effectiveCapRadius-dEnd;float cy=effectiveCapRadius-dSide;float cornerDist=sqrt(cx*cx+cy*cy);headRounding=1.0-smoothstep(effectiveCapRadius-aa,effectiveCapRadius+aa,cornerDist);}float tailRounding=1.0;if(dStart<effectiveCapRadius&&dSide<effectiveCapRadius){float cx=effectiveCapRadius-dStart;float cy=effectiveCapRadius-dSide;float cornerDist=sqrt(cx*cx+cy*cy);tailRounding=1.0-smoothstep(effectiveCapRadius-aa,effectiveCapRadius+aa,cornerDist);}float roundingAlpha=headRounding*tailRounding;float flameHeight=u_outerRadius+fireNoise*0.04*u_intensity;float ringOuter=1.0-smoothstep(flameHeight,flameHeight+0.02,radius);float ringAlpha=ringInner*ringOuter;ringAlpha*=roundingAlpha;float isVisible=0.0;if(u_progress>=0.995){isVisible=1.0;}else{float diff=progressAngle-angle;if(diff>0.0){isVisible=1.0;}}float headFade=smoothstep(0.0,0.02,progressAngle-angle);float tailFade=smoothstep(0.0,0.02,angle);if(u_progress>=0.99){tailFade=1.0;headFade=1.0;}float fillAlpha=isVisible*headFade*tailFade;if(u_progress<0.001)fillAlpha=0.0;float centerDist=abs(normRadius-0.5)*2.0;float heatMap=(fireNoise*0.5+0.5);heatMap*=(1.0-centerDist*0.5);heatMap*=(0.8+u_intensity*0.4);float relPos=angle/(progressAngle+0.001);float heatBoostHead=smoothstep(0.7,1.0,relPos)*0.4*u_intensity;float heatBoostTail=smoothstep(0.3,0.0,relPos)*0.4*u_intensity;heatMap+=heatBoostHead+heatBoostTail;float gradientPos=angle/TWO_PI;vec3 baseColor=texture(u_gradientTexture,vec2(gradientPos,0.5)).rgb;vec3 black=vec3(0.0);vec3 white=vec3(1.0);vec3 finalColor=black;if(heatMap<0.5){float t=heatMap/0.5;finalColor=mix(black,baseColor,t*t);}else{float t=(heatMap-0.5)/0.5;finalColor=mix(baseColor,white,t*t);}float finalAlpha=ringAlpha*fillAlpha;if(finalAlpha<0.01){discard;}fragColor=vec4(finalColor,finalAlpha);}";
|
|
4
4
|
|
|
5
5
|
module.exports = fragmentShaderSource;
|
|
6
6
|
//# sourceMappingURL=fragment.frag.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fragment.frag.js","sources":["../../../../../src/classes/CircularProgressFire/shaders/fragment.frag"],"sourcesContent":["#version 300 es\nprecision mediump float;\n\nin vec2 v_uv;\nout vec4 fragColor;\n\nuniform float u_time;\nuniform float u_progress;\nuniform vec2 u_resolution;\nuniform float u_innerRadius;\nuniform float u_outerRadius;\nuniform float u_startAngle;\nuniform float u_reversed;\nuniform sampler2D u_gradientTexture;\nuniform float u_intensity;\n\n#define PI 3.14159265359\n#define TWO_PI 6.28318530718\n\n// Simplex noise helper functions\nvec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }\n\nfloat snoise(vec2 v){\n const vec4 C = vec4(0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439);\n vec2 i = floor(v + dot(v, C.yy) );\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1;\n i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod(i, 289.0);\n vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))\n + i.x + vec3(0.0, i1.x, 1.0 ));\n vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);\n m = m*m ;\n m = m*m ;\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n}\n\nvoid main() {\n vec2 st = v_uv * 2.0 - 1.0;\n st.x *= u_resolution.x / u_resolution.y;\n\n float radius = length(st);\n\n // --- ANGLE CALCULATION ---\n float absAngle = atan(st.x, st.y);\n if (absAngle < 0.0) absAngle += TWO_PI;\n\n float relAngle = absAngle - u_startAngle;\n relAngle = mod(relAngle, TWO_PI);\n if (relAngle < 0.0) relAngle += TWO_PI;\n\n if (u_reversed > 0.5) {\n relAngle = TWO_PI - relAngle;\n }\n \n float angle = mod(relAngle, TWO_PI);\n float progressAngle = u_progress * TWO_PI;\n\n // --- FIRE NOISE ---\n // Make noise flow ALONG the ring (using angle) instead of radiating out\n float time = u_time * 2.0;\n \n // Coordinate system for noise:\n // We map polar coordinates to 3D space to ensure seamless looping at 0/360 degrees.\n // x,y: circle in 2D plane (based on angle)\n // z: time + radius variations\n \n float noiseFreq = 2.0; // Frequency of noise around the ring\n float radiusFreq = 3.0; // Frequency across the track width\n \n // Normalize radius to 0..1 within the track for better noise mapping\n float trackWidth = u_outerRadius - u_innerRadius;\n float normRadius = (radius - u_innerRadius) / trackWidth;\n \n // 3D Noise inputs\n // To make it loop perfectly:\n // We trace a circle in the noise space.\n float nx = cos(angle) * noiseFreq;\n float ny = sin(angle) * noiseFreq;\n // We add 'time' to Z to animate flow.\n // We add normRadius to Z to vary noise across width.\n // To make flow look like it moves along the ring, we rotate the angle with time.\n \n float flowAngle = angle - time * 0.5; // Flow direction\n float n_x = cos(flowAngle) * noiseFreq;\n float n_y = sin(flowAngle) * noiseFreq;\n float n_z = normRadius * radiusFreq; \n \n // However, we don't have snoise3. Let's fake it with snoise2 by mixing or careful mapping.\n // Or we can just use snoise2 with a clever wrapping? \n // No, snoise(vec2) is hard to wrap perfectly without artifacts unless we use 4D noise projected to 2D loop.\n // BUT, we can use the standard trick: mix two noise samples? No.\n \n // Let's implement a simple psuedo-3D noise or just use the domain wrapping trick with 2D noise:\n // Noise(x, y) where x is cos(a), y is sin(a) -> this loops!\n // But we need animation (time).\n // We can animate the domain offset? No.\n // We can animate the Z? We don't have Z.\n \n // Workaround with 2D noise for looping 1D domain + time:\n // We need 3 dimensions: Angle(loop), Radius(non-loop), Time(linear).\n // We can use 2D noise for (AngleLoop, Time).\n // AngleLoop needs 2 coords (cos, sin). So we need 3D noise.\n \n // Since we only have snoise(vec2) included, let's just use the coordinate mapping that minimizes the seam\n // OR accept that we need a better noise function.\n // Let's stick to snoise(vec2) but map it carefully.\n // Actually, let's just use the polar mapping:\n // noise(cos(a)*R + time, sin(a)*R) -> this distorts.\n \n // Better approach with what we have:\n // Let's use the polar coordinates directly but \"blend\" the seam at 0/2PI.\n // We sample noise at 'angle' and 'angle - 2PI' and mix them? \n \n // Let's try a simple Polar projection into 2D plane which rotates.\n // This is seamless by definition.\n vec2 polarUV = vec2(cos(angle), sin(angle)) * (2.0 + normRadius) - vec2(time, time * 0.5);\n // This rotates the noise field. It is seamless.\n \n // Main flame shape noise\n float n = snoise(polarUV * 1.5);\n \n // Detail noise (rotate faster/different direction)\n vec2 polarUV2 = vec2(cos(angle + 1.0), sin(angle + 1.0)) * (3.0 + normRadius * 2.0) - vec2(time * 1.5, -time);\n float n2 = snoise(polarUV2 * 2.0);\n \n float fireNoise = n * 0.6 + n2 * 0.4; // Range approx -1 to 1\n \n // --- RING SHAPE & MASK ---\n // Hard clamp at inner radius, soft fade at outer\n float ringInner = smoothstep(u_innerRadius - 0.01, u_innerRadius, radius);\n \n // Border radius effect\n // We want the \"head\" and \"tail\" to be rounded.\n // Distance from the center line of the track\n float trackCenter = (u_innerRadius + u_outerRadius) * 0.5;\n float distFromCenter = abs(radius - trackCenter);\n float halfWidth = (u_outerRadius - u_innerRadius) * 0.5;\n \n // Cap radius (rounding)\n // We want full rounding when progress is small, and diminishing rounding as it approaches 100%\n // Actually, simple rounded caps are just distance checks from the end points in Cartesian space.\n // But in polar, we can approximate.\n \n // Arc length at center radius\n float arcLen = trackCenter * progressAngle;\n float capRadius = halfWidth; // Full rounding radius\n \n // Reduce rounding radius as we near completion to make it seamless\n // Start reducing at 90% progress?\n float roundingFactor = 1.0;\n if (u_progress > 0.9) {\n roundingFactor = (1.0 - u_progress) * 10.0; // 1.0 at 0.9, 0.0 at 1.0\n }\n \n float effectiveCapRadius = capRadius * roundingFactor;\n \n // To implement caps in shader without expensive cartesian distance:\n // We use the angle distance converted to arc length.\n \n float distToHeadArc = (progressAngle - angle) * trackCenter;\n float distToTailArc = angle * trackCenter;\n \n // Check if we are in the \"cap zone\"\n // Head Cap\n float headAlpha = 1.0;\n if (distToHeadArc < effectiveCapRadius && distToHeadArc > -effectiveCapRadius) {\n // We are near the head.\n // Distance from the \"cap center\" point\n // Cap center is at angle = progressAngle - (capRadius/R) ? No, cap center is at the end of the bar.\n // Actually, a round cap usually extends OUT or is cut IN.\n // Let's assume \"inset\" caps or just rounding the corners?\n // Standard \"round\" lineCap extends beyond the endpoint by radius.\n // Here, let's round the CORNERS of the cut.\n \n // Let's model a circle at the end point.\n // End point in polar: (progressAngle, trackCenter)\n // Current point: (angle, radius)\n \n // Approximate distance in 2D (valid for small angles)\n float dX = (progressAngle - angle) * trackCenter;\n float dY = radius - trackCenter;\n float distToCapCenter = sqrt(dX*dX + dY*dY);\n \n // If we are \"ahead\" of the cut line, we mask? No, we want to round the cut.\n // Let's mask anything beyond the line, BUT add the circle.\n \n // Simplified: \n // 1. Mask everything beyond progressAngle (handled by headFade logic mostly)\n // 2. Except if inside the cap circle at the end.\n \n // But user wants \"border-radius like\", maybe just rounding the corners of the flat cut?\n // Let's assume we want a full semi-circle cap.\n \n // It's easier to mask everything > progressAngle, and add a circle at progressAngle.\n // BUT, we need to fade out this effect.\n \n // Let's use the \"Alpha\" we already computed (fillAlpha) which defines the cut.\n // And modify it.\n }\n \n // Simpler approach for \"Border Radius\" style effect on the cut:\n // We modify the opacity based on distance from the corner.\n \n // But wait, we are doing Fire. The edge is already soft.\n // User wants a \"rounded\" shape at the ends.\n \n // Let's use a Signed Distance Field (SDF) approach for the bar tips.\n \n // Tip 1: Head\n float dHeadX = (angle - progressAngle) * trackCenter; // Positive ahead, negative behind\n float dHeadY = abs(radius - trackCenter); // Distance from center line\n \n // SDF for a box with one rounded end? Or just a circle at the end?\n // Let's define the shape as: (Bar) U (Circle at Head) U (Circle at Tail)\n // Bar is defined by angles 0..progressAngle.\n // Circle Head at (progressAngle). Circle Tail at (0).\n \n // But we want the circle radius to shrink.\n \n float capCircleRadius = halfWidth * roundingFactor;\n \n // Check head circle\n float dX_head = (angle - progressAngle) * trackCenter;\n float dY_cap = radius - trackCenter;\n float distHeadSq = dX_head*dX_head + dY_cap*dY_cap;\n \n // Check tail circle\n float dX_tail = (angle - 0.0) * trackCenter;\n float distTailSq = dX_tail*dX_tail + dY_cap*dY_cap;\n \n // Modify visibility\n // Standard bar is angle <= progressAngle && angle >= 0\n // We want to ERODE the corners? Or EXTEND?\n // Usually border-radius on a progress bar means the ends are rounded.\n // So the effective bar is shorter, and we have caps.\n \n // Let's treat the bar as:\n // Rect from [capRadius/L] to [progress - capRadius/L]\n // + Circle at start + Circle at end.\n \n // This effectively \"shrinks\" the visual bar if we keep angles same.\n \n // Let's just apply a mask that rounds the corners of the existing sector.\n // Distance from the \"Corner\" (intersection of radial cut and outer/inner rings).\n \n // It's getting complicated for a shader without proper SDF.\n // Let's try a visual trick.\n // Smoothstep the alpha based on distance to the \"end line\" combined with distance to edge.\n \n // Distance to Head Line: (progressAngle - angle) * trackCenter\n // Distance to Edge (side): halfWidth - abs(radius - trackCenter)\n \n float dEnd = (progressAngle - angle) * trackCenter;\n float dStart = angle * trackCenter;\n float dSide = halfWidth - abs(radius - trackCenter);\n \n // We want the alpha to be 0 if sqrt(dEnd^2 + dSide^2) < radius (inverted corner)?\n // No, standard rounded rect logic: \n // Alpha = smoothstep(radius, radius-1, distance_from_inner_rect)\n \n // Let's model the tip as a rounded box shape SDF in 2D local space of the tip.\n // Tip space: x = distance from end, y = distance from center.\n // We want to round the corners where x -> 0 and y -> halfWidth.\n \n // Head Rounding\n float headRounding = 1.0;\n if (dEnd < effectiveCapRadius && dSide < effectiveCapRadius) {\n // Inside the corner zone\n float cx = effectiveCapRadius - dEnd;\n float cy = effectiveCapRadius - dSide;\n float cornerDist = sqrt(cx*cx + cy*cy);\n headRounding = 1.0 - smoothstep(effectiveCapRadius - 0.005, effectiveCapRadius + 0.005, cornerDist);\n }\n \n // Tail Rounding\n float tailRounding = 1.0;\n if (dStart < effectiveCapRadius && dSide < effectiveCapRadius) {\n float cx = effectiveCapRadius - dStart;\n float cy = effectiveCapRadius - dSide;\n float cornerDist = sqrt(cx*cx + cy*cy);\n tailRounding = 1.0 - smoothstep(effectiveCapRadius - 0.005, effectiveCapRadius + 0.005, cornerDist);\n }\n \n float roundingAlpha = headRounding * tailRounding;\n\n // The \"flame\" height varies.\n // We modify the effective outer radius with noise.\n // Base outer limit is u_outerRadius.\n // Flames can lick slightly outside, but we want to contain them mostly.\n \n // To prevent clipping, we should ensure u_outerRadius passed from JS leaves room.\n // But if we want strict bounds, we fade out before the edge.\n \n float flameHeight = u_outerRadius + fireNoise * 0.04 * u_intensity;\n float ringOuter = smoothstep(flameHeight, flameHeight + 0.02, radius);\n \n float ringAlpha = ringInner - ringOuter;\n ringAlpha = clamp(ringAlpha, 0.0, 1.0);\n \n // Apply rounding\n ringAlpha *= roundingAlpha;\n\n // --- PROGRESS FILL LOGIC ---\n // The \"head\" is the leading edge of the fire.\n \n float headNoise = snoise(vec2(time * 5.0, radius * 10.0)) * 0.05 * u_intensity;\n \n // Determine if a pixel is within the active arc\n // We need to handle the \"tail\" (start) and \"head\" (end) of the progress.\n // 0 to progressAngle.\n \n float isVisible = 0.0;\n \n // Handle the wrap-around case for looping 100%\n // If progress is ~1.0, we want full circle without a seam at 0/360\n if (u_progress >= 0.995) {\n isVisible = 1.0;\n } else {\n // Basic check: angle < progressAngle?\n // But we also want the head to have noise.\n \n float effectiveAngle = angle;\n // If we are very close to 0, and progress is near 1, we might have issues, but standard angle logic works 0..2PI\n \n float diff = progressAngle - angle;\n // Add noise to the boundary\n if (diff > 0.0) {\n isVisible = 1.0;\n }\n \n // Hard cut at exactly 0 if we want? \n // Or let the tail fade in?\n // Let's fade the tail (near angle 0).\n }\n\n // Soft head edge\n // Use sharper transition if we have rounding, but user asked for rounding.\n // The fade logic conflicts slightly with solid rounding.\n // Let's reduce the fade width to make the rounding visible.\n float headFade = smoothstep(0.0, 0.02, progressAngle - angle);\n \n // Soft tail edge (fade in from 0)\n // We want the start of the fire (at angle 0) to not be a hard cut line, but a soft rise.\n \n // Calculate tailFade similarly to headFade but reversed\n // angle > 0.0 essentially.\n // We want to mask out where angle < 0 (which doesn't happen in 0..2PI space directly, but close to 0 it matters)\n \n float tailFade = smoothstep(0.0, 0.02, angle);\n \n // If looping (progress ~ 1), we don't want tailFade to cut the loop at 0.\n if (u_progress >= 0.99) {\n tailFade = 1.0;\n headFade = 1.0;\n }\n\n // Combine transparency\n float fillAlpha = isVisible * headFade * tailFade;\n \n // Ensure 0 progress is empty\n if (u_progress < 0.001) fillAlpha = 0.0;\n\n // --- COLORING ---\n // Fire color palette\n // Deep Red -> Orange -> Yellow -> White (Hot)\n \n // Map noise and radius to color heat\n // Heat is higher in the center of the track and lower at edges\n float centerDist = abs(normRadius - 0.5) * 2.0; // 0 at center, 1 at edges\n float heatMap = (fireNoise * 0.5 + 0.5); // 0..1\n \n // Modulate heat by track position (hottest in middle)\n heatMap *= (1.0 - centerDist * 0.5);\n \n // Modulate by intensity\n heatMap *= (0.8 + u_intensity * 0.4);\n \n // Make the head AND tail hotter\n // Normalize angle to 0..1 relative to progress\n float relPos = angle / (progressAngle + 0.001);\n \n // Boost heat at the head (relPos near 1)\n float heatBoostHead = smoothstep(0.7, 1.0, relPos) * 0.4 * u_intensity;\n \n // Boost heat at the tail (relPos near 0)\n float heatBoostTail = smoothstep(0.3, 0.0, relPos) * 0.4 * u_intensity;\n \n // Apply boosts\n heatMap += heatBoostHead + heatBoostTail;\n \n \n // Color interpolation from gradient texture\n // Map angle (0..2PI) to UV (0..1)\n float gradientPos = angle / TWO_PI;\n vec3 baseColor = texture(u_gradientTexture, vec2(gradientPos, 0.5)).rgb;\n\n vec3 black = vec3(0.0);\n vec3 white = vec3(1.0);\n \n vec3 finalColor = black;\n \n // Heat map coloring strategy:\n // 0.0 - 0.3: Black -> Dark Base\n // 0.3 - 0.6: Dark Base -> Base\n // 0.6 - 0.8: Base -> Bright Base\n // 0.8 - 1.0: Bright Base -> White\n\n // Simplified 3-stage:\n // Low heat: Black -> Base\n // High heat: Base -> White\n\n if (heatMap < 0.5) {\n // Darker phase\n // Power function to keep it dark longer\n float t = heatMap / 0.5;\n finalColor = mix(black, baseColor, t * t); \n } else {\n // Brighter phase\n float t = (heatMap - 0.5) / 0.5;\n // Mix to white\n finalColor = mix(baseColor, white, t * t);\n }\n \n // Alpha composition\n float finalAlpha = ringAlpha * fillAlpha;\n \n // Fade out the tail end of the color intensity slightly?\n // Optional: make the \"start\" of the bar colder and \"head\" hotter\n \n fragColor = vec4(finalColor, finalAlpha);\n}\n\n"],"names":[],"mappings":";;AAAA,2BAAe,6kKAA6kK;;;;"}
|
|
1
|
+
{"version":3,"file":"fragment.frag.js","sources":["../../../../../src/classes/CircularProgressFire/shaders/fragment.frag"],"sourcesContent":["#version 300 es\n// Using highp to prevent coordinate jitter on mobile devices\nprecision highp float;\n\nin vec2 v_uv;\nout vec4 fragColor;\n\nuniform float u_time;\nuniform float u_progress;\nuniform vec2 u_resolution;\nuniform float u_innerRadius;\nuniform float u_outerRadius;\nuniform float u_startAngle;\nuniform float u_reversed;\nuniform sampler2D u_gradientTexture;\nuniform float u_intensity;\n\n#define PI 3.14159265359\n#define TWO_PI 6.28318530718\n\n// Simplex noise helper functions\nvec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }\n\nfloat snoise(vec2 v){\n const vec4 C = vec4(0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439);\n vec2 i = floor(v + dot(v, C.yy) );\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1;\n i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod(i, 289.0);\n vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))\n + i.x + vec3(0.0, i1.x, 1.0 ));\n vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);\n m = m*m ;\n m = m*m ;\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n}\n\nvoid main() {\n vec2 st = v_uv * 2.0 - 1.0;\n\n // FIX 1: Safe aspect ratio correction\n if (u_resolution.y > 0.0) {\n st.x *= u_resolution.x / u_resolution.y;\n }\n\n float radius = length(st);\n\n // --- ANGLE CALCULATION ---\n float absAngle = atan(st.x, st.y);\n if (absAngle < 0.0) absAngle += TWO_PI;\n\n float relAngle = absAngle - u_startAngle;\n relAngle = mod(relAngle, TWO_PI);\n if (relAngle < 0.0) relAngle += TWO_PI;\n\n if (u_reversed > 0.5) {\n relAngle = TWO_PI - relAngle;\n }\n\n float angle = mod(relAngle, TWO_PI);\n float progressAngle = u_progress * TWO_PI;\n\n // --- FIRE NOISE ---\n float time = u_time * 2.0;\n\n float noiseFreq = 2.0;\n float radiusFreq = 3.0;\n\n float trackWidth = u_outerRadius - u_innerRadius;\n float normRadius = (radius - u_innerRadius) / trackWidth;\n\n // Polar projection into 2D plane for seamless looping\n vec2 polarUV = vec2(cos(angle), sin(angle)) * (2.0 + normRadius) - vec2(time, time * 0.5);\n float n = snoise(polarUV * 1.5);\n\n vec2 polarUV2 = vec2(cos(angle + 1.0), sin(angle + 1.0)) * (3.0 + normRadius * 2.0) - vec2(time * 1.5, -time);\n float n2 = snoise(polarUV2 * 2.0);\n\n float fireNoise = n * 0.6 + n2 * 0.4;\n\n // --- RING SHAPE & MASK ---\n\n // FIX 2: Adaptive Anti-Aliasing (AA) for sharp edges on mobile\n float aa = max(2.0 / u_resolution.y, 0.002);\n\n // Inner Edge Mask\n float ringInner = smoothstep(u_innerRadius - aa, u_innerRadius, radius);\n\n // Border radius / Cap logic\n float trackCenter = (u_innerRadius + u_outerRadius) * 0.5;\n float halfWidth = (u_outerRadius - u_innerRadius) * 0.5;\n float capRadius = halfWidth;\n\n float roundingFactor = 1.0;\n if (u_progress > 0.9) {\n roundingFactor = (1.0 - u_progress) * 10.0;\n }\n\n float effectiveCapRadius = capRadius * roundingFactor;\n\n float dEnd = (progressAngle - angle) * trackCenter;\n float dStart = angle * trackCenter;\n float dSide = halfWidth - abs(radius - trackCenter);\n\n // Head Rounding\n float headRounding = 1.0;\n if (dEnd < effectiveCapRadius && dSide < effectiveCapRadius) {\n float cx = effectiveCapRadius - dEnd;\n float cy = effectiveCapRadius - dSide;\n float cornerDist = sqrt(cx*cx + cy*cy);\n headRounding = 1.0 - smoothstep(effectiveCapRadius - aa, effectiveCapRadius + aa, cornerDist);\n }\n\n // Tail Rounding\n float tailRounding = 1.0;\n if (dStart < effectiveCapRadius && dSide < effectiveCapRadius) {\n float cx = effectiveCapRadius - dStart;\n float cy = effectiveCapRadius - dSide;\n float cornerDist = sqrt(cx*cx + cy*cy);\n tailRounding = 1.0 - smoothstep(effectiveCapRadius - aa, effectiveCapRadius + aa, cornerDist);\n }\n\n float roundingAlpha = headRounding * tailRounding;\n\n // Fire/Flame outer edge\n float flameHeight = u_outerRadius + fireNoise * 0.04 * u_intensity;\n\n // FIX 3: Robust masking using multiplication instead of subtraction\n // Invert smoothstep for the outer edge\n float ringOuter = 1.0 - smoothstep(flameHeight, flameHeight + 0.02, radius);\n\n // Combine masks\n float ringAlpha = ringInner * ringOuter;\n\n // Apply rounding\n ringAlpha *= roundingAlpha;\n\n // --- PROGRESS FILL LOGIC ---\n float isVisible = 0.0;\n\n if (u_progress >= 0.995) {\n isVisible = 1.0;\n } else {\n float diff = progressAngle - angle;\n if (diff > 0.0) {\n isVisible = 1.0;\n }\n }\n\n float headFade = smoothstep(0.0, 0.02, progressAngle - angle);\n float tailFade = smoothstep(0.0, 0.02, angle);\n\n if (u_progress >= 0.99) {\n tailFade = 1.0;\n headFade = 1.0;\n }\n\n float fillAlpha = isVisible * headFade * tailFade;\n\n if (u_progress < 0.001) fillAlpha = 0.0;\n\n // --- COLORING ---\n float centerDist = abs(normRadius - 0.5) * 2.0;\n float heatMap = (fireNoise * 0.5 + 0.5);\n\n heatMap *= (1.0 - centerDist * 0.5);\n heatMap *= (0.8 + u_intensity * 0.4);\n\n float relPos = angle / (progressAngle + 0.001);\n float heatBoostHead = smoothstep(0.7, 1.0, relPos) * 0.4 * u_intensity;\n float heatBoostTail = smoothstep(0.3, 0.0, relPos) * 0.4 * u_intensity;\n\n heatMap += heatBoostHead + heatBoostTail;\n\n float gradientPos = angle / TWO_PI;\n vec3 baseColor = texture(u_gradientTexture, vec2(gradientPos, 0.5)).rgb;\n\n vec3 black = vec3(0.0);\n vec3 white = vec3(1.0);\n vec3 finalColor = black;\n\n if (heatMap < 0.5) {\n float t = heatMap / 0.5;\n finalColor = mix(black, baseColor, t * t);\n } else {\n float t = (heatMap - 0.5) / 0.5;\n finalColor = mix(baseColor, white, t * t);\n }\n\n float finalAlpha = ringAlpha * fillAlpha;\n\n // FIX 4: CRITICAL FOR MOBILE\n // Discard pixels with near-zero alpha to prevent \"black square\" artifacts\n // and blending issues on iOS/Android browsers.\n if (finalAlpha < 0.01) {\n discard;\n }\n\n fragColor = vec4(finalColor, finalAlpha);\n}\n"],"names":[],"mappings":";;AAAA,2BAAe,uoIAAuoI;;;;"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
var fragmentShaderSource = "#version 300 es\nprecision
|
|
3
|
+
var fragmentShaderSource = "#version 300 es\nprecision highp float;in vec2 v_uv;out vec4 fragColor;uniform float u_flowTime;uniform float u_progress;uniform float u_velocity;uniform vec2 u_resolution;uniform sampler2D u_gradientTexture;uniform float u_innerRadius;uniform float u_outerRadius;uniform float u_reversed;uniform float u_startAngle;uniform float u_volume;\n#define PI 3.14159265359\n#define TWO_PI 6.28318530718\nfloat random(vec2 p){vec3 p3=fract(vec3(p.xyx)*.1031);p3+=dot(p3,p3.yzx+33.33);return fract((p3.x+p3.y)*p3.z);}void main(){vec2 st=v_uv*2.0-1.0;if(u_resolution.y>0.0){st.x*=u_resolution.x/u_resolution.y;}float radius=length(st);float absAngle=atan(st.x,st.y);if(absAngle<0.0)absAngle+=TWO_PI;float relAngle=absAngle-u_startAngle;relAngle=mod(relAngle,TWO_PI);if(relAngle<0.0)relAngle+=TWO_PI;if(u_reversed>0.5){relAngle=TWO_PI-relAngle;}float angle=mod(relAngle,TWO_PI);float centerRadius=(u_innerRadius+u_outerRadius)*0.5;float trackWidth=u_outerRadius-u_innerRadius;float safeTrackWidth=max(trackWidth,0.001);float progressAngle=u_progress*TWO_PI;float flowProfile=1.0-pow(abs(radius-centerRadius)/(safeTrackWidth*0.5),2.0);flowProfile=clamp(flowProfile,0.0,1.0);float pressureBulge=u_velocity*flowProfile*1.0;float ripples=sin(radius*40.0-u_flowTime*15.0)*0.03*abs(u_velocity);float activeBoundary=progressAngle+pressureBulge+ripples;float halfWidth=safeTrackWidth*0.5;float trackCenter=centerRadius;float capRadius=halfWidth;float roundingFactor=1.0;if(u_progress>0.9){roundingFactor=(1.0-u_progress)*10.0;}float effectiveCapRadius=capRadius*roundingFactor;float dEnd=(activeBoundary-angle)*trackCenter;float dStart=angle*trackCenter;float dSide=halfWidth-abs(radius-trackCenter);float capSoftness=0.01;float headRounding=1.0;if(dEnd<effectiveCapRadius&&dSide<effectiveCapRadius){float cx=effectiveCapRadius-dEnd;float cy=effectiveCapRadius-dSide;float cornerDist=sqrt(cx*cx+cy*cy);headRounding=1.0-smoothstep(effectiveCapRadius-capSoftness,effectiveCapRadius+capSoftness,cornerDist);}float tailRounding=1.0;if(dStart<effectiveCapRadius&&dSide<effectiveCapRadius){float cx=effectiveCapRadius-dStart;float cy=effectiveCapRadius-dSide;float cornerDist=sqrt(cx*cx+cy*cy);tailRounding=1.0-smoothstep(effectiveCapRadius-capSoftness,effectiveCapRadius+capSoftness,cornerDist);}float roundingAlpha=headRounding*tailRounding;float fill=smoothstep(0.0,0.02,activeBoundary-angle);if(u_progress>0.99)fill=1.0;if(u_progress<0.02&&angle>6.0)fill=0.0;float aa=max(2.0/u_resolution.y,0.002);float innerEdge=smoothstep(u_innerRadius-aa,u_innerRadius,radius);float outerEdge=1.0-smoothstep(u_outerRadius,u_outerRadius+aa,radius);float ringAlpha=innerEdge*outerEdge;float t=angle/TWO_PI;vec3 waterColor=texture(u_gradientTexture,vec2(t,0.5)).rgb;float flowLines=sin(angle*20.0-u_flowTime*5.0)*sin(radius*100.0)*0.1;waterColor+=vec3(flowLines);float distToHead=abs(angle-activeBoundary);float foamThickness=0.02+abs(u_velocity)*0.15;float foam=smoothstep(foamThickness,0.0,distToHead)*fill;float foamSuppress=1.0-smoothstep(0.95,1.0,u_progress);foam*=foamSuppress;float sparkle=random(v_uv*10.0+u_flowTime);foam*=(0.8+0.5*sparkle);vec3 finalColor=mix(waterColor,vec3(1.0),foam);float trackCenterDist=abs(radius-centerRadius)/(safeTrackWidth*0.5);float cylinderNormalZ=sqrt(max(0.0,1.0-trackCenterDist*trackCenterDist));float specular=pow(cylinderNormalZ,3.0)*0.4;float edgeShadow=smoothstep(0.8,1.0,trackCenterDist);vec3 lightedColor=finalColor+vec3(specular);lightedColor*=(1.0-edgeShadow*0.5);finalColor=mix(finalColor,lightedColor,u_volume);float finalAlpha=ringAlpha*fill*roundingAlpha;if(finalAlpha<0.01){discard;}fragColor=vec4(finalColor,finalAlpha);}";
|
|
4
4
|
|
|
5
5
|
module.exports = fragmentShaderSource;
|
|
6
6
|
//# sourceMappingURL=fragment.frag.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fragment.frag.js","sources":["../../../../../src/classes/CircularProgressLiquid/shaders/fragment.frag"],"sourcesContent":["#version 300 es\nprecision
|
|
1
|
+
{"version":3,"file":"fragment.frag.js","sources":["../../../../../src/classes/CircularProgressLiquid/shaders/fragment.frag"],"sourcesContent":["#version 300 es\n// Using highp to prevent coordinate jitter on mobile devices\nprecision highp float;\n\nin vec2 v_uv;\nout vec4 fragColor;\n\nuniform float u_flowTime;\nuniform float u_progress;\nuniform float u_velocity;\nuniform vec2 u_resolution;\nuniform sampler2D u_gradientTexture;\nuniform float u_innerRadius;\nuniform float u_outerRadius;\n\nuniform float u_reversed;\nuniform float u_startAngle;\nuniform float u_volume;\n\n#define PI 3.14159265359\n#define TWO_PI 6.28318530718\n\n// Hash function for random numbers (more stable than sine on mobile)\nfloat random(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * .1031);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n}\n\nvoid main() {\n // Normalize coordinates\n vec2 st = v_uv * 2.0 - 1.0;\n\n // Aspect ratio correction (guard against division by zero)\n if (u_resolution.y > 0.0) {\n st.x *= u_resolution.x / u_resolution.y;\n }\n\n float radius = length(st);\n\n // Angle calculation\n float absAngle = atan(st.x, st.y);\n if (absAngle < 0.0) absAngle += TWO_PI;\n\n float relAngle = absAngle - u_startAngle;\n relAngle = mod(relAngle, TWO_PI);\n if (relAngle < 0.0) relAngle += TWO_PI;\n\n if (u_reversed > 0.5) {\n relAngle = TWO_PI - relAngle;\n }\n\n float angle = mod(relAngle, TWO_PI);\n\n float centerRadius = (u_innerRadius + u_outerRadius) * 0.5;\n float trackWidth = u_outerRadius - u_innerRadius;\n float safeTrackWidth = max(trackWidth, 0.001);\n float progressAngle = u_progress * TWO_PI;\n\n // --- PHYSICS ---\n float flowProfile = 1.0 - pow(abs(radius - centerRadius) / (safeTrackWidth * 0.5), 2.0);\n flowProfile = clamp(flowProfile, 0.0, 1.0);\n\n float pressureBulge = u_velocity * flowProfile * 1.0;\n float ripples = sin(radius * 40.0 - u_flowTime * 15.0) * 0.03 * abs(u_velocity);\n\n float activeBoundary = progressAngle + pressureBulge + ripples;\n\n // --- ROUNDED CAPS ---\n float halfWidth = safeTrackWidth * 0.5;\n float trackCenter = centerRadius;\n float capRadius = halfWidth;\n\n // Rounding animation when completing the circle\n float roundingFactor = 1.0;\n if (u_progress > 0.9) {\n roundingFactor = (1.0 - u_progress) * 10.0;\n }\n float effectiveCapRadius = capRadius * roundingFactor;\n\n float dEnd = (activeBoundary - angle) * trackCenter;\n float dStart = angle * trackCenter;\n float dSide = halfWidth - abs(radius - trackCenter);\n\n // Edge smoothing for mobile (slightly softer)\n float capSoftness = 0.01;\n\n // Head rounding\n float headRounding = 1.0;\n if (dEnd < effectiveCapRadius && dSide < effectiveCapRadius) {\n float cx = effectiveCapRadius - dEnd;\n float cy = effectiveCapRadius - dSide;\n float cornerDist = sqrt(cx*cx + cy*cy);\n headRounding = 1.0 - smoothstep(effectiveCapRadius - capSoftness, effectiveCapRadius + capSoftness, cornerDist);\n }\n\n // Tail rounding\n float tailRounding = 1.0;\n if (dStart < effectiveCapRadius && dSide < effectiveCapRadius) {\n float cx = effectiveCapRadius - dStart;\n float cy = effectiveCapRadius - dSide;\n float cornerDist = sqrt(cx*cx + cy*cy);\n tailRounding = 1.0 - smoothstep(effectiveCapRadius - capSoftness, effectiveCapRadius + capSoftness, cornerDist);\n }\n\n float roundingAlpha = headRounding * tailRounding;\n\n // --- FILL ---\n float fill = smoothstep(0.0, 0.02, activeBoundary - angle);\n if (u_progress > 0.99) fill = 1.0;\n if (u_progress < 0.02 && angle > 6.0) fill = 0.0;\n\n // --- COLOR & RING MASK ---\n\n // FIX: More robust anti-aliasing (AA) calculation\n // Clamp minimum to 0.002 to prevent edges from being too sharp on 4K/Retina screens\n float aa = max(2.0 / u_resolution.y, 0.002);\n\n // FIX: Use multiplication instead of subtraction for the ring mask.\n // This is more stable on mobile GPUs.\n float innerEdge = smoothstep(u_innerRadius - aa, u_innerRadius, radius);\n float outerEdge = 1.0 - smoothstep(u_outerRadius, u_outerRadius + aa, radius);\n float ringAlpha = innerEdge * outerEdge;\n\n // Gradient\n float t = angle / TWO_PI;\n vec3 waterColor = texture(u_gradientTexture, vec2(t, 0.5)).rgb;\n\n float flowLines = sin(angle * 20.0 - u_flowTime * 5.0) * sin(radius * 100.0) * 0.1;\n waterColor += vec3(flowLines);\n\n // --- FOAM ---\n float distToHead = abs(angle - activeBoundary);\n float foamThickness = 0.02 + abs(u_velocity) * 0.15;\n float foam = smoothstep(foamThickness, 0.0, distToHead) * fill;\n float foamSuppress = 1.0 - smoothstep(0.95, 1.0, u_progress);\n foam *= foamSuppress;\n\n float sparkle = random(v_uv * 10.0 + u_flowTime);\n foam *= (0.8 + 0.5 * sparkle);\n\n vec3 finalColor = mix(waterColor, vec3(1.0), foam);\n\n // --- VOLUME ---\n float trackCenterDist = abs(radius - centerRadius) / (safeTrackWidth * 0.5);\n float cylinderNormalZ = sqrt(max(0.0, 1.0 - trackCenterDist * trackCenterDist));\n float specular = pow(cylinderNormalZ, 3.0) * 0.4;\n float edgeShadow = smoothstep(0.8, 1.0, trackCenterDist);\n vec3 lightedColor = finalColor + vec3(specular);\n lightedColor *= (1.0 - edgeShadow * 0.5);\n finalColor = mix(finalColor, lightedColor, u_volume);\n\n // --- FINAL ALPHA ---\n float finalAlpha = ringAlpha * fill * roundingAlpha;\n\n // CRITICAL FIX FOR MOBILE:\n // If alpha is very small, discard the pixel completely.\n // This solves the \"black squares\" and incorrect blending issue on iOS/Android.\n if (finalAlpha < 0.01) {\n discard;\n }\n\n fragColor = vec4(finalColor, finalAlpha);\n}\n"],"names":[],"mappings":";;AAAA,2BAAe,0jHAA0jH;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var fragmentShaderSource = "#version 300 es\nprecision
|
|
1
|
+
var fragmentShaderSource = "#version 300 es\nprecision highp float;in vec2 v_uv;out vec4 fragColor;uniform float u_time;uniform float u_progress;uniform vec2 u_resolution;uniform float u_innerRadius;uniform float u_outerRadius;uniform float u_startAngle;uniform float u_reversed;uniform sampler2D u_gradientTexture;uniform float u_intensity;\n#define PI 3.14159265359\n#define TWO_PI 6.28318530718\nvec3 permute(vec3 x){return mod(((x*34.0)+1.0)*x,289.0);}float snoise(vec2 v){const vec4 C=vec4(0.211324865405187,0.366025403784439,-0.577350269189626,0.024390243902439);vec2 i=floor(v+dot(v,C.yy));vec2 x0=v-i+dot(i,C.xx);vec2 i1;i1=(x0.x>x0.y)? vec2(1.0,0.0): vec2(0.0,1.0);vec4 x12=x0.xyxy+C.xxzz;x12.xy-=i1;i=mod(i,289.0);vec3 p=permute(permute(i.y+vec3(0.0,i1.y,1.0))+i.x+vec3(0.0,i1.x,1.0));vec3 m=max(0.5-vec3(dot(x0,x0),dot(x12.xy,x12.xy),dot(x12.zw,x12.zw)),0.0);m=m*m;m=m*m;vec3 x=2.0*fract(p*C.www)-1.0;vec3 h=abs(x)-0.5;vec3 ox=floor(x+0.5);vec3 a0=x-ox;m*=1.79284291400159-0.85373472095314*(a0*a0+h*h);vec3 g;g.x=a0.x*x0.x+h.x*x0.y;g.yz=a0.yz*x12.xz+h.yz*x12.yw;return 130.0*dot(m,g);}void main(){vec2 st=v_uv*2.0-1.0;if(u_resolution.y>0.0){st.x*=u_resolution.x/u_resolution.y;}float radius=length(st);float absAngle=atan(st.x,st.y);if(absAngle<0.0)absAngle+=TWO_PI;float relAngle=absAngle-u_startAngle;relAngle=mod(relAngle,TWO_PI);if(relAngle<0.0)relAngle+=TWO_PI;if(u_reversed>0.5){relAngle=TWO_PI-relAngle;}float angle=mod(relAngle,TWO_PI);float progressAngle=u_progress*TWO_PI;float time=u_time*2.0;float noiseFreq=2.0;float radiusFreq=3.0;float trackWidth=u_outerRadius-u_innerRadius;float normRadius=(radius-u_innerRadius)/trackWidth;vec2 polarUV=vec2(cos(angle),sin(angle))*(2.0+normRadius)-vec2(time,time*0.5);float n=snoise(polarUV*1.5);vec2 polarUV2=vec2(cos(angle+1.0),sin(angle+1.0))*(3.0+normRadius*2.0)-vec2(time*1.5,-time);float n2=snoise(polarUV2*2.0);float fireNoise=n*0.6+n2*0.4;float aa=max(2.0/u_resolution.y,0.002);float ringInner=smoothstep(u_innerRadius-aa,u_innerRadius,radius);float trackCenter=(u_innerRadius+u_outerRadius)*0.5;float halfWidth=(u_outerRadius-u_innerRadius)*0.5;float capRadius=halfWidth;float roundingFactor=1.0;if(u_progress>0.9){roundingFactor=(1.0-u_progress)*10.0;}float effectiveCapRadius=capRadius*roundingFactor;float dEnd=(progressAngle-angle)*trackCenter;float dStart=angle*trackCenter;float dSide=halfWidth-abs(radius-trackCenter);float headRounding=1.0;if(dEnd<effectiveCapRadius&&dSide<effectiveCapRadius){float cx=effectiveCapRadius-dEnd;float cy=effectiveCapRadius-dSide;float cornerDist=sqrt(cx*cx+cy*cy);headRounding=1.0-smoothstep(effectiveCapRadius-aa,effectiveCapRadius+aa,cornerDist);}float tailRounding=1.0;if(dStart<effectiveCapRadius&&dSide<effectiveCapRadius){float cx=effectiveCapRadius-dStart;float cy=effectiveCapRadius-dSide;float cornerDist=sqrt(cx*cx+cy*cy);tailRounding=1.0-smoothstep(effectiveCapRadius-aa,effectiveCapRadius+aa,cornerDist);}float roundingAlpha=headRounding*tailRounding;float flameHeight=u_outerRadius+fireNoise*0.04*u_intensity;float ringOuter=1.0-smoothstep(flameHeight,flameHeight+0.02,radius);float ringAlpha=ringInner*ringOuter;ringAlpha*=roundingAlpha;float isVisible=0.0;if(u_progress>=0.995){isVisible=1.0;}else{float diff=progressAngle-angle;if(diff>0.0){isVisible=1.0;}}float headFade=smoothstep(0.0,0.02,progressAngle-angle);float tailFade=smoothstep(0.0,0.02,angle);if(u_progress>=0.99){tailFade=1.0;headFade=1.0;}float fillAlpha=isVisible*headFade*tailFade;if(u_progress<0.001)fillAlpha=0.0;float centerDist=abs(normRadius-0.5)*2.0;float heatMap=(fireNoise*0.5+0.5);heatMap*=(1.0-centerDist*0.5);heatMap*=(0.8+u_intensity*0.4);float relPos=angle/(progressAngle+0.001);float heatBoostHead=smoothstep(0.7,1.0,relPos)*0.4*u_intensity;float heatBoostTail=smoothstep(0.3,0.0,relPos)*0.4*u_intensity;heatMap+=heatBoostHead+heatBoostTail;float gradientPos=angle/TWO_PI;vec3 baseColor=texture(u_gradientTexture,vec2(gradientPos,0.5)).rgb;vec3 black=vec3(0.0);vec3 white=vec3(1.0);vec3 finalColor=black;if(heatMap<0.5){float t=heatMap/0.5;finalColor=mix(black,baseColor,t*t);}else{float t=(heatMap-0.5)/0.5;finalColor=mix(baseColor,white,t*t);}float finalAlpha=ringAlpha*fillAlpha;if(finalAlpha<0.01){discard;}fragColor=vec4(finalColor,finalAlpha);}";
|
|
2
2
|
|
|
3
3
|
export { fragmentShaderSource as default };
|
|
4
4
|
//# sourceMappingURL=fragment.frag.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fragment.frag.js","sources":["../../../../../src/classes/CircularProgressFire/shaders/fragment.frag"],"sourcesContent":["#version 300 es\nprecision mediump float;\n\nin vec2 v_uv;\nout vec4 fragColor;\n\nuniform float u_time;\nuniform float u_progress;\nuniform vec2 u_resolution;\nuniform float u_innerRadius;\nuniform float u_outerRadius;\nuniform float u_startAngle;\nuniform float u_reversed;\nuniform sampler2D u_gradientTexture;\nuniform float u_intensity;\n\n#define PI 3.14159265359\n#define TWO_PI 6.28318530718\n\n// Simplex noise helper functions\nvec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }\n\nfloat snoise(vec2 v){\n const vec4 C = vec4(0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439);\n vec2 i = floor(v + dot(v, C.yy) );\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1;\n i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod(i, 289.0);\n vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))\n + i.x + vec3(0.0, i1.x, 1.0 ));\n vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);\n m = m*m ;\n m = m*m ;\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n}\n\nvoid main() {\n vec2 st = v_uv * 2.0 - 1.0;\n st.x *= u_resolution.x / u_resolution.y;\n\n float radius = length(st);\n\n // --- ANGLE CALCULATION ---\n float absAngle = atan(st.x, st.y);\n if (absAngle < 0.0) absAngle += TWO_PI;\n\n float relAngle = absAngle - u_startAngle;\n relAngle = mod(relAngle, TWO_PI);\n if (relAngle < 0.0) relAngle += TWO_PI;\n\n if (u_reversed > 0.5) {\n relAngle = TWO_PI - relAngle;\n }\n \n float angle = mod(relAngle, TWO_PI);\n float progressAngle = u_progress * TWO_PI;\n\n // --- FIRE NOISE ---\n // Make noise flow ALONG the ring (using angle) instead of radiating out\n float time = u_time * 2.0;\n \n // Coordinate system for noise:\n // We map polar coordinates to 3D space to ensure seamless looping at 0/360 degrees.\n // x,y: circle in 2D plane (based on angle)\n // z: time + radius variations\n \n float noiseFreq = 2.0; // Frequency of noise around the ring\n float radiusFreq = 3.0; // Frequency across the track width\n \n // Normalize radius to 0..1 within the track for better noise mapping\n float trackWidth = u_outerRadius - u_innerRadius;\n float normRadius = (radius - u_innerRadius) / trackWidth;\n \n // 3D Noise inputs\n // To make it loop perfectly:\n // We trace a circle in the noise space.\n float nx = cos(angle) * noiseFreq;\n float ny = sin(angle) * noiseFreq;\n // We add 'time' to Z to animate flow.\n // We add normRadius to Z to vary noise across width.\n // To make flow look like it moves along the ring, we rotate the angle with time.\n \n float flowAngle = angle - time * 0.5; // Flow direction\n float n_x = cos(flowAngle) * noiseFreq;\n float n_y = sin(flowAngle) * noiseFreq;\n float n_z = normRadius * radiusFreq; \n \n // However, we don't have snoise3. Let's fake it with snoise2 by mixing or careful mapping.\n // Or we can just use snoise2 with a clever wrapping? \n // No, snoise(vec2) is hard to wrap perfectly without artifacts unless we use 4D noise projected to 2D loop.\n // BUT, we can use the standard trick: mix two noise samples? No.\n \n // Let's implement a simple psuedo-3D noise or just use the domain wrapping trick with 2D noise:\n // Noise(x, y) where x is cos(a), y is sin(a) -> this loops!\n // But we need animation (time).\n // We can animate the domain offset? No.\n // We can animate the Z? We don't have Z.\n \n // Workaround with 2D noise for looping 1D domain + time:\n // We need 3 dimensions: Angle(loop), Radius(non-loop), Time(linear).\n // We can use 2D noise for (AngleLoop, Time).\n // AngleLoop needs 2 coords (cos, sin). So we need 3D noise.\n \n // Since we only have snoise(vec2) included, let's just use the coordinate mapping that minimizes the seam\n // OR accept that we need a better noise function.\n // Let's stick to snoise(vec2) but map it carefully.\n // Actually, let's just use the polar mapping:\n // noise(cos(a)*R + time, sin(a)*R) -> this distorts.\n \n // Better approach with what we have:\n // Let's use the polar coordinates directly but \"blend\" the seam at 0/2PI.\n // We sample noise at 'angle' and 'angle - 2PI' and mix them? \n \n // Let's try a simple Polar projection into 2D plane which rotates.\n // This is seamless by definition.\n vec2 polarUV = vec2(cos(angle), sin(angle)) * (2.0 + normRadius) - vec2(time, time * 0.5);\n // This rotates the noise field. It is seamless.\n \n // Main flame shape noise\n float n = snoise(polarUV * 1.5);\n \n // Detail noise (rotate faster/different direction)\n vec2 polarUV2 = vec2(cos(angle + 1.0), sin(angle + 1.0)) * (3.0 + normRadius * 2.0) - vec2(time * 1.5, -time);\n float n2 = snoise(polarUV2 * 2.0);\n \n float fireNoise = n * 0.6 + n2 * 0.4; // Range approx -1 to 1\n \n // --- RING SHAPE & MASK ---\n // Hard clamp at inner radius, soft fade at outer\n float ringInner = smoothstep(u_innerRadius - 0.01, u_innerRadius, radius);\n \n // Border radius effect\n // We want the \"head\" and \"tail\" to be rounded.\n // Distance from the center line of the track\n float trackCenter = (u_innerRadius + u_outerRadius) * 0.5;\n float distFromCenter = abs(radius - trackCenter);\n float halfWidth = (u_outerRadius - u_innerRadius) * 0.5;\n \n // Cap radius (rounding)\n // We want full rounding when progress is small, and diminishing rounding as it approaches 100%\n // Actually, simple rounded caps are just distance checks from the end points in Cartesian space.\n // But in polar, we can approximate.\n \n // Arc length at center radius\n float arcLen = trackCenter * progressAngle;\n float capRadius = halfWidth; // Full rounding radius\n \n // Reduce rounding radius as we near completion to make it seamless\n // Start reducing at 90% progress?\n float roundingFactor = 1.0;\n if (u_progress > 0.9) {\n roundingFactor = (1.0 - u_progress) * 10.0; // 1.0 at 0.9, 0.0 at 1.0\n }\n \n float effectiveCapRadius = capRadius * roundingFactor;\n \n // To implement caps in shader without expensive cartesian distance:\n // We use the angle distance converted to arc length.\n \n float distToHeadArc = (progressAngle - angle) * trackCenter;\n float distToTailArc = angle * trackCenter;\n \n // Check if we are in the \"cap zone\"\n // Head Cap\n float headAlpha = 1.0;\n if (distToHeadArc < effectiveCapRadius && distToHeadArc > -effectiveCapRadius) {\n // We are near the head.\n // Distance from the \"cap center\" point\n // Cap center is at angle = progressAngle - (capRadius/R) ? No, cap center is at the end of the bar.\n // Actually, a round cap usually extends OUT or is cut IN.\n // Let's assume \"inset\" caps or just rounding the corners?\n // Standard \"round\" lineCap extends beyond the endpoint by radius.\n // Here, let's round the CORNERS of the cut.\n \n // Let's model a circle at the end point.\n // End point in polar: (progressAngle, trackCenter)\n // Current point: (angle, radius)\n \n // Approximate distance in 2D (valid for small angles)\n float dX = (progressAngle - angle) * trackCenter;\n float dY = radius - trackCenter;\n float distToCapCenter = sqrt(dX*dX + dY*dY);\n \n // If we are \"ahead\" of the cut line, we mask? No, we want to round the cut.\n // Let's mask anything beyond the line, BUT add the circle.\n \n // Simplified: \n // 1. Mask everything beyond progressAngle (handled by headFade logic mostly)\n // 2. Except if inside the cap circle at the end.\n \n // But user wants \"border-radius like\", maybe just rounding the corners of the flat cut?\n // Let's assume we want a full semi-circle cap.\n \n // It's easier to mask everything > progressAngle, and add a circle at progressAngle.\n // BUT, we need to fade out this effect.\n \n // Let's use the \"Alpha\" we already computed (fillAlpha) which defines the cut.\n // And modify it.\n }\n \n // Simpler approach for \"Border Radius\" style effect on the cut:\n // We modify the opacity based on distance from the corner.\n \n // But wait, we are doing Fire. The edge is already soft.\n // User wants a \"rounded\" shape at the ends.\n \n // Let's use a Signed Distance Field (SDF) approach for the bar tips.\n \n // Tip 1: Head\n float dHeadX = (angle - progressAngle) * trackCenter; // Positive ahead, negative behind\n float dHeadY = abs(radius - trackCenter); // Distance from center line\n \n // SDF for a box with one rounded end? Or just a circle at the end?\n // Let's define the shape as: (Bar) U (Circle at Head) U (Circle at Tail)\n // Bar is defined by angles 0..progressAngle.\n // Circle Head at (progressAngle). Circle Tail at (0).\n \n // But we want the circle radius to shrink.\n \n float capCircleRadius = halfWidth * roundingFactor;\n \n // Check head circle\n float dX_head = (angle - progressAngle) * trackCenter;\n float dY_cap = radius - trackCenter;\n float distHeadSq = dX_head*dX_head + dY_cap*dY_cap;\n \n // Check tail circle\n float dX_tail = (angle - 0.0) * trackCenter;\n float distTailSq = dX_tail*dX_tail + dY_cap*dY_cap;\n \n // Modify visibility\n // Standard bar is angle <= progressAngle && angle >= 0\n // We want to ERODE the corners? Or EXTEND?\n // Usually border-radius on a progress bar means the ends are rounded.\n // So the effective bar is shorter, and we have caps.\n \n // Let's treat the bar as:\n // Rect from [capRadius/L] to [progress - capRadius/L]\n // + Circle at start + Circle at end.\n \n // This effectively \"shrinks\" the visual bar if we keep angles same.\n \n // Let's just apply a mask that rounds the corners of the existing sector.\n // Distance from the \"Corner\" (intersection of radial cut and outer/inner rings).\n \n // It's getting complicated for a shader without proper SDF.\n // Let's try a visual trick.\n // Smoothstep the alpha based on distance to the \"end line\" combined with distance to edge.\n \n // Distance to Head Line: (progressAngle - angle) * trackCenter\n // Distance to Edge (side): halfWidth - abs(radius - trackCenter)\n \n float dEnd = (progressAngle - angle) * trackCenter;\n float dStart = angle * trackCenter;\n float dSide = halfWidth - abs(radius - trackCenter);\n \n // We want the alpha to be 0 if sqrt(dEnd^2 + dSide^2) < radius (inverted corner)?\n // No, standard rounded rect logic: \n // Alpha = smoothstep(radius, radius-1, distance_from_inner_rect)\n \n // Let's model the tip as a rounded box shape SDF in 2D local space of the tip.\n // Tip space: x = distance from end, y = distance from center.\n // We want to round the corners where x -> 0 and y -> halfWidth.\n \n // Head Rounding\n float headRounding = 1.0;\n if (dEnd < effectiveCapRadius && dSide < effectiveCapRadius) {\n // Inside the corner zone\n float cx = effectiveCapRadius - dEnd;\n float cy = effectiveCapRadius - dSide;\n float cornerDist = sqrt(cx*cx + cy*cy);\n headRounding = 1.0 - smoothstep(effectiveCapRadius - 0.005, effectiveCapRadius + 0.005, cornerDist);\n }\n \n // Tail Rounding\n float tailRounding = 1.0;\n if (dStart < effectiveCapRadius && dSide < effectiveCapRadius) {\n float cx = effectiveCapRadius - dStart;\n float cy = effectiveCapRadius - dSide;\n float cornerDist = sqrt(cx*cx + cy*cy);\n tailRounding = 1.0 - smoothstep(effectiveCapRadius - 0.005, effectiveCapRadius + 0.005, cornerDist);\n }\n \n float roundingAlpha = headRounding * tailRounding;\n\n // The \"flame\" height varies.\n // We modify the effective outer radius with noise.\n // Base outer limit is u_outerRadius.\n // Flames can lick slightly outside, but we want to contain them mostly.\n \n // To prevent clipping, we should ensure u_outerRadius passed from JS leaves room.\n // But if we want strict bounds, we fade out before the edge.\n \n float flameHeight = u_outerRadius + fireNoise * 0.04 * u_intensity;\n float ringOuter = smoothstep(flameHeight, flameHeight + 0.02, radius);\n \n float ringAlpha = ringInner - ringOuter;\n ringAlpha = clamp(ringAlpha, 0.0, 1.0);\n \n // Apply rounding\n ringAlpha *= roundingAlpha;\n\n // --- PROGRESS FILL LOGIC ---\n // The \"head\" is the leading edge of the fire.\n \n float headNoise = snoise(vec2(time * 5.0, radius * 10.0)) * 0.05 * u_intensity;\n \n // Determine if a pixel is within the active arc\n // We need to handle the \"tail\" (start) and \"head\" (end) of the progress.\n // 0 to progressAngle.\n \n float isVisible = 0.0;\n \n // Handle the wrap-around case for looping 100%\n // If progress is ~1.0, we want full circle without a seam at 0/360\n if (u_progress >= 0.995) {\n isVisible = 1.0;\n } else {\n // Basic check: angle < progressAngle?\n // But we also want the head to have noise.\n \n float effectiveAngle = angle;\n // If we are very close to 0, and progress is near 1, we might have issues, but standard angle logic works 0..2PI\n \n float diff = progressAngle - angle;\n // Add noise to the boundary\n if (diff > 0.0) {\n isVisible = 1.0;\n }\n \n // Hard cut at exactly 0 if we want? \n // Or let the tail fade in?\n // Let's fade the tail (near angle 0).\n }\n\n // Soft head edge\n // Use sharper transition if we have rounding, but user asked for rounding.\n // The fade logic conflicts slightly with solid rounding.\n // Let's reduce the fade width to make the rounding visible.\n float headFade = smoothstep(0.0, 0.02, progressAngle - angle);\n \n // Soft tail edge (fade in from 0)\n // We want the start of the fire (at angle 0) to not be a hard cut line, but a soft rise.\n \n // Calculate tailFade similarly to headFade but reversed\n // angle > 0.0 essentially.\n // We want to mask out where angle < 0 (which doesn't happen in 0..2PI space directly, but close to 0 it matters)\n \n float tailFade = smoothstep(0.0, 0.02, angle);\n \n // If looping (progress ~ 1), we don't want tailFade to cut the loop at 0.\n if (u_progress >= 0.99) {\n tailFade = 1.0;\n headFade = 1.0;\n }\n\n // Combine transparency\n float fillAlpha = isVisible * headFade * tailFade;\n \n // Ensure 0 progress is empty\n if (u_progress < 0.001) fillAlpha = 0.0;\n\n // --- COLORING ---\n // Fire color palette\n // Deep Red -> Orange -> Yellow -> White (Hot)\n \n // Map noise and radius to color heat\n // Heat is higher in the center of the track and lower at edges\n float centerDist = abs(normRadius - 0.5) * 2.0; // 0 at center, 1 at edges\n float heatMap = (fireNoise * 0.5 + 0.5); // 0..1\n \n // Modulate heat by track position (hottest in middle)\n heatMap *= (1.0 - centerDist * 0.5);\n \n // Modulate by intensity\n heatMap *= (0.8 + u_intensity * 0.4);\n \n // Make the head AND tail hotter\n // Normalize angle to 0..1 relative to progress\n float relPos = angle / (progressAngle + 0.001);\n \n // Boost heat at the head (relPos near 1)\n float heatBoostHead = smoothstep(0.7, 1.0, relPos) * 0.4 * u_intensity;\n \n // Boost heat at the tail (relPos near 0)\n float heatBoostTail = smoothstep(0.3, 0.0, relPos) * 0.4 * u_intensity;\n \n // Apply boosts\n heatMap += heatBoostHead + heatBoostTail;\n \n \n // Color interpolation from gradient texture\n // Map angle (0..2PI) to UV (0..1)\n float gradientPos = angle / TWO_PI;\n vec3 baseColor = texture(u_gradientTexture, vec2(gradientPos, 0.5)).rgb;\n\n vec3 black = vec3(0.0);\n vec3 white = vec3(1.0);\n \n vec3 finalColor = black;\n \n // Heat map coloring strategy:\n // 0.0 - 0.3: Black -> Dark Base\n // 0.3 - 0.6: Dark Base -> Base\n // 0.6 - 0.8: Base -> Bright Base\n // 0.8 - 1.0: Bright Base -> White\n\n // Simplified 3-stage:\n // Low heat: Black -> Base\n // High heat: Base -> White\n\n if (heatMap < 0.5) {\n // Darker phase\n // Power function to keep it dark longer\n float t = heatMap / 0.5;\n finalColor = mix(black, baseColor, t * t); \n } else {\n // Brighter phase\n float t = (heatMap - 0.5) / 0.5;\n // Mix to white\n finalColor = mix(baseColor, white, t * t);\n }\n \n // Alpha composition\n float finalAlpha = ringAlpha * fillAlpha;\n \n // Fade out the tail end of the color intensity slightly?\n // Optional: make the \"start\" of the bar colder and \"head\" hotter\n \n fragColor = vec4(finalColor, finalAlpha);\n}\n\n"],"names":[],"mappings":"AAAA,2BAAe,6kKAA6kK;;;;"}
|
|
1
|
+
{"version":3,"file":"fragment.frag.js","sources":["../../../../../src/classes/CircularProgressFire/shaders/fragment.frag"],"sourcesContent":["#version 300 es\n// Using highp to prevent coordinate jitter on mobile devices\nprecision highp float;\n\nin vec2 v_uv;\nout vec4 fragColor;\n\nuniform float u_time;\nuniform float u_progress;\nuniform vec2 u_resolution;\nuniform float u_innerRadius;\nuniform float u_outerRadius;\nuniform float u_startAngle;\nuniform float u_reversed;\nuniform sampler2D u_gradientTexture;\nuniform float u_intensity;\n\n#define PI 3.14159265359\n#define TWO_PI 6.28318530718\n\n// Simplex noise helper functions\nvec3 permute(vec3 x) { return mod(((x*34.0)+1.0)*x, 289.0); }\n\nfloat snoise(vec2 v){\n const vec4 C = vec4(0.211324865405187, 0.366025403784439,\n -0.577350269189626, 0.024390243902439);\n vec2 i = floor(v + dot(v, C.yy) );\n vec2 x0 = v - i + dot(i, C.xx);\n vec2 i1;\n i1 = (x0.x > x0.y) ? vec2(1.0, 0.0) : vec2(0.0, 1.0);\n vec4 x12 = x0.xyxy + C.xxzz;\n x12.xy -= i1;\n i = mod(i, 289.0);\n vec3 p = permute( permute( i.y + vec3(0.0, i1.y, 1.0 ))\n + i.x + vec3(0.0, i1.x, 1.0 ));\n vec3 m = max(0.5 - vec3(dot(x0,x0), dot(x12.xy,x12.xy), dot(x12.zw,x12.zw)), 0.0);\n m = m*m ;\n m = m*m ;\n vec3 x = 2.0 * fract(p * C.www) - 1.0;\n vec3 h = abs(x) - 0.5;\n vec3 ox = floor(x + 0.5);\n vec3 a0 = x - ox;\n m *= 1.79284291400159 - 0.85373472095314 * ( a0*a0 + h*h );\n vec3 g;\n g.x = a0.x * x0.x + h.x * x0.y;\n g.yz = a0.yz * x12.xz + h.yz * x12.yw;\n return 130.0 * dot(m, g);\n}\n\nvoid main() {\n vec2 st = v_uv * 2.0 - 1.0;\n\n // FIX 1: Safe aspect ratio correction\n if (u_resolution.y > 0.0) {\n st.x *= u_resolution.x / u_resolution.y;\n }\n\n float radius = length(st);\n\n // --- ANGLE CALCULATION ---\n float absAngle = atan(st.x, st.y);\n if (absAngle < 0.0) absAngle += TWO_PI;\n\n float relAngle = absAngle - u_startAngle;\n relAngle = mod(relAngle, TWO_PI);\n if (relAngle < 0.0) relAngle += TWO_PI;\n\n if (u_reversed > 0.5) {\n relAngle = TWO_PI - relAngle;\n }\n\n float angle = mod(relAngle, TWO_PI);\n float progressAngle = u_progress * TWO_PI;\n\n // --- FIRE NOISE ---\n float time = u_time * 2.0;\n\n float noiseFreq = 2.0;\n float radiusFreq = 3.0;\n\n float trackWidth = u_outerRadius - u_innerRadius;\n float normRadius = (radius - u_innerRadius) / trackWidth;\n\n // Polar projection into 2D plane for seamless looping\n vec2 polarUV = vec2(cos(angle), sin(angle)) * (2.0 + normRadius) - vec2(time, time * 0.5);\n float n = snoise(polarUV * 1.5);\n\n vec2 polarUV2 = vec2(cos(angle + 1.0), sin(angle + 1.0)) * (3.0 + normRadius * 2.0) - vec2(time * 1.5, -time);\n float n2 = snoise(polarUV2 * 2.0);\n\n float fireNoise = n * 0.6 + n2 * 0.4;\n\n // --- RING SHAPE & MASK ---\n\n // FIX 2: Adaptive Anti-Aliasing (AA) for sharp edges on mobile\n float aa = max(2.0 / u_resolution.y, 0.002);\n\n // Inner Edge Mask\n float ringInner = smoothstep(u_innerRadius - aa, u_innerRadius, radius);\n\n // Border radius / Cap logic\n float trackCenter = (u_innerRadius + u_outerRadius) * 0.5;\n float halfWidth = (u_outerRadius - u_innerRadius) * 0.5;\n float capRadius = halfWidth;\n\n float roundingFactor = 1.0;\n if (u_progress > 0.9) {\n roundingFactor = (1.0 - u_progress) * 10.0;\n }\n\n float effectiveCapRadius = capRadius * roundingFactor;\n\n float dEnd = (progressAngle - angle) * trackCenter;\n float dStart = angle * trackCenter;\n float dSide = halfWidth - abs(radius - trackCenter);\n\n // Head Rounding\n float headRounding = 1.0;\n if (dEnd < effectiveCapRadius && dSide < effectiveCapRadius) {\n float cx = effectiveCapRadius - dEnd;\n float cy = effectiveCapRadius - dSide;\n float cornerDist = sqrt(cx*cx + cy*cy);\n headRounding = 1.0 - smoothstep(effectiveCapRadius - aa, effectiveCapRadius + aa, cornerDist);\n }\n\n // Tail Rounding\n float tailRounding = 1.0;\n if (dStart < effectiveCapRadius && dSide < effectiveCapRadius) {\n float cx = effectiveCapRadius - dStart;\n float cy = effectiveCapRadius - dSide;\n float cornerDist = sqrt(cx*cx + cy*cy);\n tailRounding = 1.0 - smoothstep(effectiveCapRadius - aa, effectiveCapRadius + aa, cornerDist);\n }\n\n float roundingAlpha = headRounding * tailRounding;\n\n // Fire/Flame outer edge\n float flameHeight = u_outerRadius + fireNoise * 0.04 * u_intensity;\n\n // FIX 3: Robust masking using multiplication instead of subtraction\n // Invert smoothstep for the outer edge\n float ringOuter = 1.0 - smoothstep(flameHeight, flameHeight + 0.02, radius);\n\n // Combine masks\n float ringAlpha = ringInner * ringOuter;\n\n // Apply rounding\n ringAlpha *= roundingAlpha;\n\n // --- PROGRESS FILL LOGIC ---\n float isVisible = 0.0;\n\n if (u_progress >= 0.995) {\n isVisible = 1.0;\n } else {\n float diff = progressAngle - angle;\n if (diff > 0.0) {\n isVisible = 1.0;\n }\n }\n\n float headFade = smoothstep(0.0, 0.02, progressAngle - angle);\n float tailFade = smoothstep(0.0, 0.02, angle);\n\n if (u_progress >= 0.99) {\n tailFade = 1.0;\n headFade = 1.0;\n }\n\n float fillAlpha = isVisible * headFade * tailFade;\n\n if (u_progress < 0.001) fillAlpha = 0.0;\n\n // --- COLORING ---\n float centerDist = abs(normRadius - 0.5) * 2.0;\n float heatMap = (fireNoise * 0.5 + 0.5);\n\n heatMap *= (1.0 - centerDist * 0.5);\n heatMap *= (0.8 + u_intensity * 0.4);\n\n float relPos = angle / (progressAngle + 0.001);\n float heatBoostHead = smoothstep(0.7, 1.0, relPos) * 0.4 * u_intensity;\n float heatBoostTail = smoothstep(0.3, 0.0, relPos) * 0.4 * u_intensity;\n\n heatMap += heatBoostHead + heatBoostTail;\n\n float gradientPos = angle / TWO_PI;\n vec3 baseColor = texture(u_gradientTexture, vec2(gradientPos, 0.5)).rgb;\n\n vec3 black = vec3(0.0);\n vec3 white = vec3(1.0);\n vec3 finalColor = black;\n\n if (heatMap < 0.5) {\n float t = heatMap / 0.5;\n finalColor = mix(black, baseColor, t * t);\n } else {\n float t = (heatMap - 0.5) / 0.5;\n finalColor = mix(baseColor, white, t * t);\n }\n\n float finalAlpha = ringAlpha * fillAlpha;\n\n // FIX 4: CRITICAL FOR MOBILE\n // Discard pixels with near-zero alpha to prevent \"black square\" artifacts\n // and blending issues on iOS/Android browsers.\n if (finalAlpha < 0.01) {\n discard;\n }\n\n fragColor = vec4(finalColor, finalAlpha);\n}\n"],"names":[],"mappings":"AAAA,2BAAe,uoIAAuoI;;;;"}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var fragmentShaderSource = "#version 300 es\nprecision
|
|
1
|
+
var fragmentShaderSource = "#version 300 es\nprecision highp float;in vec2 v_uv;out vec4 fragColor;uniform float u_flowTime;uniform float u_progress;uniform float u_velocity;uniform vec2 u_resolution;uniform sampler2D u_gradientTexture;uniform float u_innerRadius;uniform float u_outerRadius;uniform float u_reversed;uniform float u_startAngle;uniform float u_volume;\n#define PI 3.14159265359\n#define TWO_PI 6.28318530718\nfloat random(vec2 p){vec3 p3=fract(vec3(p.xyx)*.1031);p3+=dot(p3,p3.yzx+33.33);return fract((p3.x+p3.y)*p3.z);}void main(){vec2 st=v_uv*2.0-1.0;if(u_resolution.y>0.0){st.x*=u_resolution.x/u_resolution.y;}float radius=length(st);float absAngle=atan(st.x,st.y);if(absAngle<0.0)absAngle+=TWO_PI;float relAngle=absAngle-u_startAngle;relAngle=mod(relAngle,TWO_PI);if(relAngle<0.0)relAngle+=TWO_PI;if(u_reversed>0.5){relAngle=TWO_PI-relAngle;}float angle=mod(relAngle,TWO_PI);float centerRadius=(u_innerRadius+u_outerRadius)*0.5;float trackWidth=u_outerRadius-u_innerRadius;float safeTrackWidth=max(trackWidth,0.001);float progressAngle=u_progress*TWO_PI;float flowProfile=1.0-pow(abs(radius-centerRadius)/(safeTrackWidth*0.5),2.0);flowProfile=clamp(flowProfile,0.0,1.0);float pressureBulge=u_velocity*flowProfile*1.0;float ripples=sin(radius*40.0-u_flowTime*15.0)*0.03*abs(u_velocity);float activeBoundary=progressAngle+pressureBulge+ripples;float halfWidth=safeTrackWidth*0.5;float trackCenter=centerRadius;float capRadius=halfWidth;float roundingFactor=1.0;if(u_progress>0.9){roundingFactor=(1.0-u_progress)*10.0;}float effectiveCapRadius=capRadius*roundingFactor;float dEnd=(activeBoundary-angle)*trackCenter;float dStart=angle*trackCenter;float dSide=halfWidth-abs(radius-trackCenter);float capSoftness=0.01;float headRounding=1.0;if(dEnd<effectiveCapRadius&&dSide<effectiveCapRadius){float cx=effectiveCapRadius-dEnd;float cy=effectiveCapRadius-dSide;float cornerDist=sqrt(cx*cx+cy*cy);headRounding=1.0-smoothstep(effectiveCapRadius-capSoftness,effectiveCapRadius+capSoftness,cornerDist);}float tailRounding=1.0;if(dStart<effectiveCapRadius&&dSide<effectiveCapRadius){float cx=effectiveCapRadius-dStart;float cy=effectiveCapRadius-dSide;float cornerDist=sqrt(cx*cx+cy*cy);tailRounding=1.0-smoothstep(effectiveCapRadius-capSoftness,effectiveCapRadius+capSoftness,cornerDist);}float roundingAlpha=headRounding*tailRounding;float fill=smoothstep(0.0,0.02,activeBoundary-angle);if(u_progress>0.99)fill=1.0;if(u_progress<0.02&&angle>6.0)fill=0.0;float aa=max(2.0/u_resolution.y,0.002);float innerEdge=smoothstep(u_innerRadius-aa,u_innerRadius,radius);float outerEdge=1.0-smoothstep(u_outerRadius,u_outerRadius+aa,radius);float ringAlpha=innerEdge*outerEdge;float t=angle/TWO_PI;vec3 waterColor=texture(u_gradientTexture,vec2(t,0.5)).rgb;float flowLines=sin(angle*20.0-u_flowTime*5.0)*sin(radius*100.0)*0.1;waterColor+=vec3(flowLines);float distToHead=abs(angle-activeBoundary);float foamThickness=0.02+abs(u_velocity)*0.15;float foam=smoothstep(foamThickness,0.0,distToHead)*fill;float foamSuppress=1.0-smoothstep(0.95,1.0,u_progress);foam*=foamSuppress;float sparkle=random(v_uv*10.0+u_flowTime);foam*=(0.8+0.5*sparkle);vec3 finalColor=mix(waterColor,vec3(1.0),foam);float trackCenterDist=abs(radius-centerRadius)/(safeTrackWidth*0.5);float cylinderNormalZ=sqrt(max(0.0,1.0-trackCenterDist*trackCenterDist));float specular=pow(cylinderNormalZ,3.0)*0.4;float edgeShadow=smoothstep(0.8,1.0,trackCenterDist);vec3 lightedColor=finalColor+vec3(specular);lightedColor*=(1.0-edgeShadow*0.5);finalColor=mix(finalColor,lightedColor,u_volume);float finalAlpha=ringAlpha*fill*roundingAlpha;if(finalAlpha<0.01){discard;}fragColor=vec4(finalColor,finalAlpha);}";
|
|
2
2
|
|
|
3
3
|
export { fragmentShaderSource as default };
|
|
4
4
|
//# sourceMappingURL=fragment.frag.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fragment.frag.js","sources":["../../../../../src/classes/CircularProgressLiquid/shaders/fragment.frag"],"sourcesContent":["#version 300 es\nprecision
|
|
1
|
+
{"version":3,"file":"fragment.frag.js","sources":["../../../../../src/classes/CircularProgressLiquid/shaders/fragment.frag"],"sourcesContent":["#version 300 es\n// Using highp to prevent coordinate jitter on mobile devices\nprecision highp float;\n\nin vec2 v_uv;\nout vec4 fragColor;\n\nuniform float u_flowTime;\nuniform float u_progress;\nuniform float u_velocity;\nuniform vec2 u_resolution;\nuniform sampler2D u_gradientTexture;\nuniform float u_innerRadius;\nuniform float u_outerRadius;\n\nuniform float u_reversed;\nuniform float u_startAngle;\nuniform float u_volume;\n\n#define PI 3.14159265359\n#define TWO_PI 6.28318530718\n\n// Hash function for random numbers (more stable than sine on mobile)\nfloat random(vec2 p) {\n vec3 p3 = fract(vec3(p.xyx) * .1031);\n p3 += dot(p3, p3.yzx + 33.33);\n return fract((p3.x + p3.y) * p3.z);\n}\n\nvoid main() {\n // Normalize coordinates\n vec2 st = v_uv * 2.0 - 1.0;\n\n // Aspect ratio correction (guard against division by zero)\n if (u_resolution.y > 0.0) {\n st.x *= u_resolution.x / u_resolution.y;\n }\n\n float radius = length(st);\n\n // Angle calculation\n float absAngle = atan(st.x, st.y);\n if (absAngle < 0.0) absAngle += TWO_PI;\n\n float relAngle = absAngle - u_startAngle;\n relAngle = mod(relAngle, TWO_PI);\n if (relAngle < 0.0) relAngle += TWO_PI;\n\n if (u_reversed > 0.5) {\n relAngle = TWO_PI - relAngle;\n }\n\n float angle = mod(relAngle, TWO_PI);\n\n float centerRadius = (u_innerRadius + u_outerRadius) * 0.5;\n float trackWidth = u_outerRadius - u_innerRadius;\n float safeTrackWidth = max(trackWidth, 0.001);\n float progressAngle = u_progress * TWO_PI;\n\n // --- PHYSICS ---\n float flowProfile = 1.0 - pow(abs(radius - centerRadius) / (safeTrackWidth * 0.5), 2.0);\n flowProfile = clamp(flowProfile, 0.0, 1.0);\n\n float pressureBulge = u_velocity * flowProfile * 1.0;\n float ripples = sin(radius * 40.0 - u_flowTime * 15.0) * 0.03 * abs(u_velocity);\n\n float activeBoundary = progressAngle + pressureBulge + ripples;\n\n // --- ROUNDED CAPS ---\n float halfWidth = safeTrackWidth * 0.5;\n float trackCenter = centerRadius;\n float capRadius = halfWidth;\n\n // Rounding animation when completing the circle\n float roundingFactor = 1.0;\n if (u_progress > 0.9) {\n roundingFactor = (1.0 - u_progress) * 10.0;\n }\n float effectiveCapRadius = capRadius * roundingFactor;\n\n float dEnd = (activeBoundary - angle) * trackCenter;\n float dStart = angle * trackCenter;\n float dSide = halfWidth - abs(radius - trackCenter);\n\n // Edge smoothing for mobile (slightly softer)\n float capSoftness = 0.01;\n\n // Head rounding\n float headRounding = 1.0;\n if (dEnd < effectiveCapRadius && dSide < effectiveCapRadius) {\n float cx = effectiveCapRadius - dEnd;\n float cy = effectiveCapRadius - dSide;\n float cornerDist = sqrt(cx*cx + cy*cy);\n headRounding = 1.0 - smoothstep(effectiveCapRadius - capSoftness, effectiveCapRadius + capSoftness, cornerDist);\n }\n\n // Tail rounding\n float tailRounding = 1.0;\n if (dStart < effectiveCapRadius && dSide < effectiveCapRadius) {\n float cx = effectiveCapRadius - dStart;\n float cy = effectiveCapRadius - dSide;\n float cornerDist = sqrt(cx*cx + cy*cy);\n tailRounding = 1.0 - smoothstep(effectiveCapRadius - capSoftness, effectiveCapRadius + capSoftness, cornerDist);\n }\n\n float roundingAlpha = headRounding * tailRounding;\n\n // --- FILL ---\n float fill = smoothstep(0.0, 0.02, activeBoundary - angle);\n if (u_progress > 0.99) fill = 1.0;\n if (u_progress < 0.02 && angle > 6.0) fill = 0.0;\n\n // --- COLOR & RING MASK ---\n\n // FIX: More robust anti-aliasing (AA) calculation\n // Clamp minimum to 0.002 to prevent edges from being too sharp on 4K/Retina screens\n float aa = max(2.0 / u_resolution.y, 0.002);\n\n // FIX: Use multiplication instead of subtraction for the ring mask.\n // This is more stable on mobile GPUs.\n float innerEdge = smoothstep(u_innerRadius - aa, u_innerRadius, radius);\n float outerEdge = 1.0 - smoothstep(u_outerRadius, u_outerRadius + aa, radius);\n float ringAlpha = innerEdge * outerEdge;\n\n // Gradient\n float t = angle / TWO_PI;\n vec3 waterColor = texture(u_gradientTexture, vec2(t, 0.5)).rgb;\n\n float flowLines = sin(angle * 20.0 - u_flowTime * 5.0) * sin(radius * 100.0) * 0.1;\n waterColor += vec3(flowLines);\n\n // --- FOAM ---\n float distToHead = abs(angle - activeBoundary);\n float foamThickness = 0.02 + abs(u_velocity) * 0.15;\n float foam = smoothstep(foamThickness, 0.0, distToHead) * fill;\n float foamSuppress = 1.0 - smoothstep(0.95, 1.0, u_progress);\n foam *= foamSuppress;\n\n float sparkle = random(v_uv * 10.0 + u_flowTime);\n foam *= (0.8 + 0.5 * sparkle);\n\n vec3 finalColor = mix(waterColor, vec3(1.0), foam);\n\n // --- VOLUME ---\n float trackCenterDist = abs(radius - centerRadius) / (safeTrackWidth * 0.5);\n float cylinderNormalZ = sqrt(max(0.0, 1.0 - trackCenterDist * trackCenterDist));\n float specular = pow(cylinderNormalZ, 3.0) * 0.4;\n float edgeShadow = smoothstep(0.8, 1.0, trackCenterDist);\n vec3 lightedColor = finalColor + vec3(specular);\n lightedColor *= (1.0 - edgeShadow * 0.5);\n finalColor = mix(finalColor, lightedColor, u_volume);\n\n // --- FINAL ALPHA ---\n float finalAlpha = ringAlpha * fill * roundingAlpha;\n\n // CRITICAL FIX FOR MOBILE:\n // If alpha is very small, discard the pixel completely.\n // This solves the \"black squares\" and incorrect blending issue on iOS/Android.\n if (finalAlpha < 0.01) {\n discard;\n }\n\n fragColor = vec4(finalColor, finalAlpha);\n}\n"],"names":[],"mappings":"AAAA,2BAAe,0jHAA0jH;;;;"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@webeach/gl-circular-progress",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"author": {
|
|
5
5
|
"name": "Ruslan Martynov",
|
|
6
6
|
"email": "github@webea.ch"
|
|
@@ -66,17 +66,17 @@
|
|
|
66
66
|
]
|
|
67
67
|
},
|
|
68
68
|
"devDependencies": {
|
|
69
|
-
"@commitlint/cli": "^
|
|
70
|
-
"@commitlint/config-conventional": "^
|
|
69
|
+
"@commitlint/cli": "^20.0.0",
|
|
70
|
+
"@commitlint/config-conventional": "^20.0.0",
|
|
71
71
|
"@eslint/js": "^9.35.0",
|
|
72
|
-
"@rollup/plugin-commonjs": "^
|
|
72
|
+
"@rollup/plugin-commonjs": "^29.0.0",
|
|
73
73
|
"@rollup/plugin-node-resolve": "^16.0.1",
|
|
74
74
|
"@rollup/plugin-typescript": "^12.1.4",
|
|
75
75
|
"@semantic-release/changelog": "^6.0.3",
|
|
76
76
|
"@semantic-release/commit-analyzer": "^13.0.1",
|
|
77
77
|
"@semantic-release/git": "^10.0.1",
|
|
78
|
-
"@semantic-release/github": "^
|
|
79
|
-
"@semantic-release/npm": "^
|
|
78
|
+
"@semantic-release/github": "^12.0.0",
|
|
79
|
+
"@semantic-release/npm": "^13.0.0",
|
|
80
80
|
"@semantic-release/release-notes-generator": "^14.1.0",
|
|
81
81
|
"@testing-library/dom": "^10.4.1",
|
|
82
82
|
"@testing-library/user-event": "^14.6.1",
|
|
@@ -86,7 +86,7 @@
|
|
|
86
86
|
"eslint-plugin-prettier": "^5.5.4",
|
|
87
87
|
"eslint-plugin-simple-import-sort": "^12.1.1",
|
|
88
88
|
"fast-glob": "^3.3.3",
|
|
89
|
-
"globals": "^
|
|
89
|
+
"globals": "^17.0.0",
|
|
90
90
|
"husky": "^9.1.7",
|
|
91
91
|
"is-ci": "^4.1.0",
|
|
92
92
|
"lint-staged": "^16.1.6",
|
|
@@ -95,11 +95,11 @@
|
|
|
95
95
|
"rollup-plugin-glsl": "^1.3.0",
|
|
96
96
|
"rollup-plugin-node-externals": "^8.1.1",
|
|
97
97
|
"rollup-plugin-typescript2": "^0.36.0",
|
|
98
|
-
"semantic-release": "^
|
|
98
|
+
"semantic-release": "^25.0.0",
|
|
99
99
|
"tsx": "^4.20.5",
|
|
100
100
|
"typescript": "^5.9.2",
|
|
101
101
|
"typescript-eslint": "^8.43.0",
|
|
102
|
-
"vitest": "^
|
|
102
|
+
"vitest": "^4.0.0"
|
|
103
103
|
},
|
|
104
104
|
"exports": {
|
|
105
105
|
".": {
|