A simple effect on buttons with a little help of artificial intelligence.
// with a little help with artificial inteligence
// ============================================================================
// HELPER FUNCTIONS
// ============================================================================
// Matrix for 2D rotation (useful if you want to rotate internal effects)
mat2 rotate2d(float angle){
return mat2(
cos(angle), -sin(angle),
sin(angle), cos(angle)
);
}
// Signed Distance Field (SDF) for a rectangle with independent corner radii
// r.x = Top-Right, r.y = Bottom-Right, r.z = Top-Left, r.w = Bottom-Left
float sdRoundedBox( in vec2 p, in vec2 b, in vec4 r )
{
r.xy = (p.x > 0.0) ? r.xy : r.zw;
r.x = (p.y > 0.0) ? r.x : r.y;
vec2 q = abs(p) - b + r.x;
return min(max(q.x, q.y), 0.0) + length(max(q, 0.0)) - r.x;
}
// ============================================================================
// MAIN SHADERTOY ENTRY POINT
// ============================================================================
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
// 1. Normalize coordinates (from 0.0 to 1.0)
vec2 uv = fragCoord / iResolution.xy;
float ratio = iResolution.x / iResolution.y;
// 2. Define the Color Palette (Sci-Fi / Neon Theme)
vec3 backgroundColor = vec3(0.06, 0.06, 0.09); // Dark background
vec3 buttonBaseColor = vec3(0.05, 0.18, 0.35); // Base body fill color
vec3 neonBlue = vec3(0.27, 0.67, 1.0); // Sharp border stroke
vec3 aquaGlow = vec3(0.0, 0.95, 1.0); // Outer aura glow
vec3 finalColor = backgroundColor;
// 3. Split the screen into a 2x3 grid (2 columns, 3 rows) to show 6 variations
vec2 gridSize = vec2(2.0, 3.0);
vec2 gridId = floor(uv * gridSize);
// Localize UV coordinates inside each grid cell, and center the origin (0,0)
vec2 localUV = fract(uv * gridSize) - 0.5;
// Adjust aspect ratio locally for the 2x3 grid mapping
float localRatio = (iResolution.x / gridSize.x) / (iResolution.y / gridSize.y);
localUV.x *= localRatio;
// 4. Define Button Size (scaled for the 2x3 grid layout)
vec2 buttonSize = vec2(0.38, 0.13);
// 5. Initialize the corner radii vector
// Format: vec4(Top-Right, Bottom-Right, Top-Left, Bottom-Left)
vec4 cornerRadii = vec4(0.0);
// 6. Assign a different combination to each grid area (Rows from bottom=0 to top=2)
if (gridId.y == 2.0) // === TOP ROW ===
{
if (gridId.x == 0.0) {
// [TOP-LEFT]: All corners rounded equally (Standard Pill Button)
cornerRadii = vec4(0.07, 0.07, 0.07, 0.07);
} else {
// [TOP-RIGHT]: Sharp rectangular button (No rounding)
cornerRadii = vec4(0.00, 0.00, 0.00, 0.00);
}
}
else if (gridId.y == 1.0) // === MIDDLE ROW (THE LEAF DIAGONALS) ===
{
if (gridId.x == 0.0) {
// [MIDDLE-LEFT]: Leaf Style 1 (Top-Right and Bottom-Left rounded)
cornerRadii = vec4(0.15, 0.00, 0.00, 0.15);
} else {
// [MIDDLE-RIGHT]: Leaf Style 2 (Top-Left and Bottom-Right rounded)
cornerRadii = vec4(0.00, 0.15, 0.15, 0.00);
}
}
else if (gridId.y == 0.0) // === BOTTOM ROW ===
{
if (gridId.x == 0.0) {
// [BOTTOM-LEFT]: Tab Style (Top corners rounded only)
cornerRadii = vec4(0.08, 0.00, 0.08, 0.00);
} else {
// [BOTTOM-RIGHT]: Asymmetric single corner rounded
cornerRadii = vec4(0.00, 0.00, 0.16, 0.00);
}
}
// 7. Calculate the distance field for the current button shape
float d = sdRoundedBox(localUV, buttonSize, cornerRadii);
// 8. Render Button Body (Fill with a clean vertical light-to-dark gradient)
float fillMask = smoothstep(0.003, 0.0, d);
vec3 buttonBody = buttonBaseColor * (1.1 - (localUV.y + 0.5) * 0.4);
finalColor = mix(finalColor, buttonBody, fillMask);
// 9. Render Sharp Neon Border (Stroke)
float borderThickness = 0.004;
float borderMask = smoothstep(borderThickness, 0.0, abs(d)) * smoothstep(d, d + 0.004, 0.0);
finalColor += borderMask * neonBlue * 1.8;
// 10. Render Dynamic External Glow Effect (Pulses over time using iTime)
float pulse = sin(iTime * 3.5) * 0.12 + 0.88;
float glowIntensity = exp(-max(d, 0.0) * 28.0) * pulse;
finalColor += glowIntensity * aquaGlow * 0.5 * (1.0 - fillMask);
// 11. Render Internal Scanline Laser Effect
if (d < 0.0)
{
// Laser position sweeps horizontally across the local cell width
float scanSpeed = 0.5;
float scanX = fract(iTime * scanSpeed) * 2.2 - 1.1;
// Render the vertical beam profile
float scanlineWidth = 0.07;
float scanline = smoothstep(scanlineWidth, 0.0, abs((localUV.x / localRatio) - scanX));
// Add reflection overlay inside the button
finalColor += scanline * neonBlue * 0.45;
// Add inner vignette shadow
float innerShadow = smoothstep(-0.06, 0.0, d);
finalColor -= vec3(0.15) * innerShadow;
}
// 12. Draw grid lines to separate the 6 showcase zones clean
float gridLines = smoothstep(0.004, 0.0, abs(uv.x - 0.5)) +
smoothstep(0.004, 0.0, abs(uv.y - 0.3333)) +
smoothstep(0.004, 0.0, abs(uv.y - 0.6666));
finalColor = mix(finalColor, vec3(0.15, 0.15, 0.2), gridLines * 0.4);
// 13. Output processed pixels to screen
fragColor = vec4(finalColor, 1.0);
}Let's see the result: