JSFiddle - React, Tailwind, and code Playground

by jacomyal

HTML

<script src="https://rawgithub.com/html5rocks/www.html5rocks.com/bd6830fd1ec987ef8f614eed4255a3c57737a3c4/content/tutorials/webgl/webgl_fundamentals/static/webgl/resources/webgl-utils.js"></script>
<body>
<canvas id="white"></canvas>
<canvas id="black"></canvas>
<script id="2d-vertex-shader" type="x-shader/x-vertex">
  attribute vec2 a_position;
  attribute vec2 a_customAttributes;

  uniform vec2 u_resolution;
  varying vec4 color;

  void main() {
    // Scale from [[-1 1] [-1 1]] to the container:
    gl_Position = vec4((a_position / u_resolution * 2.0 - 1.0) * vec2(1, -1), 0, 1);
    gl_PointSize = a_customAttributes[0] * 2.0;

    float c = a_customAttributes[1];

    // Extract the color:
    color.b = mod(c, 256.0); c = floor(c / 256.0);
    color.g = mod(c, 256.0); c = floor(c / 256.0);
    color.r = mod(c, 256.0); c = floor(c / 256.0);
    color /= 255.0;
    color.a = 1.0;
  }
</script>
<script id="2d-fragment-shader" type="x-shader/x-fragment">
  precision mediump float;
  varying vec4 color;

  void main(void) {
    float border = 0.03;
    float radius = 0.5;
    vec4 color0 = vec4(0.0, 0.0, 0.0, 0.0);

    vec2 m = gl_PointCoord - vec2(0.5, 0.5);
    float dist = radius - sqrt(m.x * m.x + m.y * m.y);

    float t = 0.0;
    if (dist > border)
      t = 1.0;
    else if (dist > 0.0)
      t = dist / border;

    gl_FragColor = mix(color0, color, t);
  }
</script>
</body>

CSS

body {
    background: #ccc;
}
#white {
    background: #fff;
}
#black {
    background: #000;
}

JavaScript

// Get A WebGL context
function draw(canvas) {
    var gl = canvas.getContext('experimental-webgl'),
        buffer,
        matrix;
    
    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
    gl.enable(gl.BLEND);
    
    // Setup a GLSL program
    var vertexShader = createShaderFromScriptElement(gl, '2d-vertex-shader'),
        fragmentShader = createShaderFromScriptElement(gl, '2d-fragment-shader'),
        program = createProgram(gl, [vertexShader, fragmentShader]);
    
    gl.useProgram(program);
    
    // Look up where the vertex data needs to go
    var positionLocation = gl.getAttribLocation(program, 'a_position'),
        customAttributesLocation = gl.getAttribLocation(program, 'a_customAttributes'),
        resolutionLocation = gl.getUniformLocation(program, 'u_resolution');
    
    gl.enableVertexAttribArray(positionLocation);
    gl.enableVertexAttribArray(customAttributesLocation);
    gl.uniform2f(resolutionLocation, canvas.width, canvas.height);
    
    matrix = [
        40, 40, 25, 0x333333,
        75, 40, 25, 0xcccccc,
        
        40, 110, 25, 0xcccccc,
        75, 110, 25, 0x333333,
        
        150, 40, 25, 0xcccccc,
        185, 40, 25, 0xcccccc,
        
        150, 110, 25, 0x333333,
        185, 110, 25, 0x333333
    ];
    
    buffer = gl.createBuffer();
    gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
    gl.bufferData(
        gl.ARRAY_BUFFER,
        new Float32Array(matrix),
        gl.DYNAMIC_DRAW);
    
    gl.vertexAttribPointer(
      positionLocation,
      2,
      gl.FLOAT,
      false,
      4 * Float32Array.BYTES_PER_ELEMENT,
      0
    );
    gl.vertexAttribPointer(
      customAttributesLocation,
      2,
      gl.FLOAT,
      false,
      4 * Float32Array.BYTES_PER_ELEMENT,
      8
    );
    
    // Draw
    gl.drawArrays(gl.POINTS, 0, matrix.length / 4);
}

draw(document.getElementById('white'));
draw(document.getElementById('black'));