JSFiddle - React, Tailwind, and code Playground

by soulwire

HTML

<!-- physics -->
<script id="physics-vert" type="x-shader">
    attribute vec2 aVertexPos;
    void main() {
        gl_Position = vec4( aVertexPos, 1, 1 );
    }
</script>
<script id="physics-frag" type="x-shader">
    precision mediump float;
    uniform sampler2D uParticleData;
    uniform vec2 uViewport;
    uniform float uTime;
    void main() {
        vec4 particle = texture2D( uParticleData, gl_FragCoord.xy / uViewport );
        particle.x += sin( uTime ) * 0.005;
        particle.y += cos( uTime ) * 0.006;
        gl_FragColor = particle;
    }
</script>
<!-- render -->
<script id="render-vert" type="x-shader">
    uniform sampler2D uParticleData;
    attribute vec2 aParticleUV;
    void main() {
        vec4 particle = texture2D( uParticleData, aParticleUV );
        gl_Position = particle;
    }
</script>
<script id="render-frag" type="x-shader">
    precision mediump float;
    void main() {
        gl_FragColor = vec4(0,1,0.5,1);
    }
</script>
<!-- debug -->
<script id="debug-vert" type="x-shader">
    attribute vec2 aVertexPos;
    varying vec2 vTexCoord;
    void main() {
        vTexCoord = ( aVertexPos + 1.0 ) / 2.0; // map from xy to uv
        gl_Position = vec4( aVertexPos, 1, 1 );
    }
</script>
<script id="debug-frag" type="x-shader">
    precision mediump float;
    uniform vec2 uViewport;
    uniform sampler2D uTexture;
    varying vec2 vTexCoord;
    void main() {
        gl_FragColor = vec4( texture2D( uTexture, vTexCoord ) );
        //gl_FragColor = vec4( gl_FragCoord.xy / uViewport, 1, 1 );
    }
</script>

<canvas id="canvas" width="200" height="200"></canvas>

CSS

html, body {
    background: #f2f2f2;
}

canvas {
    border: 1px solid #ccc;
    background: #fff;
}

JavaScript

/*

"changing the bound program invalidates your previously enabled arrays anyway"
http://stackoverflow.com/questions/9146748/switch-shader-program-in-webgl

*/

// utilities

function createShader( src, type ) {
    var shader = gl.createShader( type );
    gl.shaderSource( shader, src );
    gl.compileShader( shader );
    if ( !gl.getShaderParameter( shader, gl.COMPILE_STATUS ) ) throw gl.getShaderInfoLog( shader );
    return shader;
}

function createProgram( vSrc, fSrc ) {
    var vs = createShader( vSrc, gl.VERTEX_SHADER );
    var fs = createShader( fSrc, gl.FRAGMENT_SHADER );
    var program = gl.createProgram();
    gl.attachShader( program, vs );
    gl.attachShader( program, fs );
    gl.linkProgram( program );
    if ( !gl.getProgramParameter( program, gl.LINK_STATUS ) ) throw gl.getProgramInfoLog( program );
    return program;
}

function getShader( id ) {
    return document.getElementById( id ).textContent;
}

function screenQuad() {
    /*  2___3
        |\  |
        |  \|
        0---1  */
    var buffer = gl.createBuffer();
    var vertices = [ -1, -1, 1, -1, -1, 1, 1, 1 ];
    gl.bindBuffer( gl.ARRAY_BUFFER, buffer );
    gl.bufferData( gl.ARRAY_BUFFER, new Float32Array( vertices ), gl.STATIC_DRAW );
    buffer.numItems = 4;
    buffer.itemSize = 2;
    return buffer;
}

// settings
var PARTICLE_COUNT = 16;
var PARTICLE_COUNT_SQRT = Math.sqrt( PARTICLE_COUNT );

// get context
var canvas = document.getElementById( 'canvas' );
var gl = canvas.getContext( 'experimental-webgl' );
gl.getExtension( 'OES_texture_float' );

// create programs
var physicsProg = createProgram( getShader( 'physics-vert' ), getShader( 'physics-frag' ) );
var renderProg = createProgram( getShader( 'render-vert' ), getShader( 'render-frag' ) );
var debugProg = createProgram( getShader( 'debug-vert' ), getShader( 'debug-frag' ) );

// store attribute / uniform locations
physicsProg.uParticleData = gl.getUniformLocation( physicsProg, 'uParticleData'...