<canvas id="webgl" width="1920" height="1080"></canvas>

<script id="vertexShader" type="x-shader/x-vertex">
attribute vec2 position;
void main() {
    gl_Position = vec4(position, 0.0, 1.0);
}

</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision highp float;
uniform vec2 resolution;
uniform float uTime;
float rand(vec2 n) { 
	return fract(sin(dot(n, vec2(12.9898, 4.1414))) * 43758.5453);
}
float sdCircle( vec2 p, float r )
{
  return length(p) - r;
}
void main() {
    vec3 grey = vec3(.2421875, .2421875, 0.25390625);
    float count = resolution.x / 80.;
    vec2 uv = gl_FragCoord.xy/resolution.x;
    
    vec2 cell = fract(uv * count);
    cell = 2. * cell - 1.0;
      
    vec2 idx = floor(uv * count) / count;
    float noi = rand(idx * abs(2. * sin(floor(uTime * 1.25))));
    
    float d = sdCircle(cell, .625);
  
    vec3 col = vec3(1.) - smoothstep(0.0,0.05,(d)) * vec3(1.);
    if(noi > .66) {
      col = smoothstep(0.0,0.05,(d)) * vec3(1.);
    }
    else if(noi > .33) {
      col = vec3(1.-smoothstep(0.0,0.05,abs(d)));
    }
    col = mix(vec3(1.), grey, col.x);
    gl_FragColor = vec4(vec3(col), 1.0);
}
</script>
html,
body
  height: 100%
  width: 100%
  padding: 0
  margin: 0
  
canvas
  display: block
  width: 100%
  height: 100%
    
View Compiled
class Scene
{
    constructor({ container,  vertexSource, fragmentSource })
    {
        this.gl = container.getContext('webgl')
        this.frameId = null
        this.buffers = this.initBuffers()
        this.init({ vertexSource, fragmentSource })
    }
    init({ vertexSource, fragmentSource })
    {
        const { gl } = this

        this.program = this.initShaderProgram(vertexSource, fragmentSource)
        this.data = {
            attribLocations: {
                position: gl.getAttribLocation(this.program, 'position')
            },
            uniformLocations: {
                uTime: gl.getUniformLocation(this.program, 'uTime'),
                resolution: gl.getUniformLocation(this.program, 'resolution')
            }
        }


        var then = 0;

        const render = (now) => {
            now *= 0.001;
            const deltaTime = now - then;
            then = now;

            this.drawScene(now);

            requestAnimationFrame(render);
        }
        requestAnimationFrame(render);
    }
    initBuffers() {
        const { gl } = this
        const vertices = new Float32Array([
            -1, -1,
            -1, 1,
            1, 1,

            -1, -1,
            1, 1,
            1, -1
        ])

        const vertexBuffer = gl.createBuffer()
        gl.bindBuffer(gl.ARRAY_BUFFER, vertexBuffer)
        gl.bufferData(gl.ARRAY_BUFFER, vertices, gl.STATIC_DRAW)

        return {
            position: vertexBuffer
        }
    }
    initShaderProgram(vsSource, fsSource) {
        const { gl } = this
        const vertexShader = this.loadShader(gl.VERTEX_SHADER, vsSource);
        const fragmentShader = this.loadShader(gl.FRAGMENT_SHADER, fsSource);
        const shaderProgram = gl.createProgram();
        gl.attachShader(shaderProgram, vertexShader);
        gl.attachShader(shaderProgram, fragmentShader);
        gl.linkProgram(shaderProgram);

        return shaderProgram;
    }
    loadShader(type, source) {
        const { gl } = this
        const shader = gl.createShader(type)
        gl.shaderSource(shader, source)
        gl.compileShader(shader)

        return shader;
    }
    drawScene(time) {
        const { gl, data, buffers } = this
        {
            gl.bindFramebuffer(gl.FRAMEBUFFER, null)
            gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight)

            gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT)

            gl.bindBuffer(gl.ARRAY_BUFFER, buffers.position);
            gl.vertexAttribPointer(data.attribLocations.position, 2, gl.FLOAT, false, 0, 0)
            gl.enableVertexAttribArray(data.attribLocations.position)

            gl.useProgram(this.program)
            gl.uniform1f(data.uniformLocations.uTime, time)
            gl.uniform2f(data.uniformLocations.resolution, gl.canvas.width, gl.canvas.height)
            gl.drawArrays(gl.TRIANGLES, 0, 6)
        }
    }
    destroy()
    {
        window.cancelAnimationFrame(this.frameId)
        this.gl.getExtension('WEBGL_lose_context').loseContext()
    }
}
const app = new Scene({
    container: document.body.querySelector('#webgl'),
    vertexSource: document.querySelector('script#vertexShader').textContent,
    fragmentSource: document.querySelector('script#fragmentShader').textContent
})
const handleResize = () => {
    app.gl.canvas.width = window.innerWidth
    app.gl.canvas.height = window.innerHeight
}
handleResize()
window.addEventListener('resize', handleResize, false)
View Compiled

External CSS

This Pen doesn't use any external CSS resources.

External JavaScript

This Pen doesn't use any external JavaScript resources.