Here's the code:
void main(void)
{
vec2 p = (2.0 * gl_FragCoord.xy - iResolution.xy) / min(iResolution.x, iResolution.y);
float h = length(p.xy);
float alpha = smoothstep(0.99, 1.0, h);
gl_FragColor = vec4(mix(vec3(0.0), vec3(h), alpha), 1.0);
}
{
vec2 p = (2.0 * gl_FragCoord.xy - iResolution.xy) / min(iResolution.x, iResolution.y);
float h = length(p.xy);
float alpha = smoothstep(0.99, 1.0, h);
gl_FragColor = vec4(mix(vec3(0.0), vec3(h), alpha), 1.0);
}
So p basically just scales down the coordinates of our current fragment so it's kind of like normalized device coordinates but accounts for the window dimensions.
I think h just measures the length of the current fragment from the center of the screen (note that the center of the screen is 0,0). Can also think of it as the radius.
And alpha is set to 0.0 if the length (we can also think of it as radius) is less than 0.99, set to 1.0 if the radius is greater than 1.0. Between it's interpolated between a very small value (meaning the edge of the circle will be sharp, not blurry).
And finally we set the fragment color. Remember that the mix function takes two vectors (basically two candidates for the fragment's color) and an alpha value, that we can think of the weight of the second vector. For this code it's all or nothing for each vector - as explained above, if the current fragment is within the radius of the circle then h will have been set to 0, so vec3(0.0), which is black, will be drawn. If the current fragment is outside of the radius then h will have been set to 1, so vec(h) (which is [1.0, 1.0, 1.0]) is what will be drawn, which is the part outside the circle.
Not posting a picture of a circle because we all already know what it looks like.