Shaders are written in GLSL ES, a C-like language with vector and matrix types but no implicit conversions, pointers, strings or recursion. A shader starting with #version 300 es is GLSL ES 3.00; without that line it is GLSL ES 1.00, the only version WebGL 1 accepts. A shader cannot print, so to see a value you render it into a one-pixel float texture and read it back, which GLH.evaluate() does:
// Section 3.2: run GLSL on the GPU; body assigns vec4 result, whose 4 floats are returned
GLH.evaluate = function (gl, body, declarations = '') {
gl.getExtension('EXT_color_buffer_float'); // allows RGBA32F targets
const program = GLH.program(gl, `#version 300 es
void main() { gl_Position = vec4(0.0, 0.0, 0.0, 1.0); gl_PointSize = 1.0; }`,
`#version 300 es
precision highp float; precision highp int; out vec4 result; ${declarations}
void main() { ${body} }`);
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texStorage2D(gl.TEXTURE_2D, 1, gl.RGBA32F, 1, 1); // a 1x1 float render target
gl.bindFramebuffer(gl.FRAMEBUFFER, gl.createFramebuffer());
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
gl.viewport(0, 0, 1, 1);
gl.useProgram(program);
gl.drawArrays(gl.POINTS, 0, 1); // one fragment runs body
const values = new Float32Array(4);
gl.readPixels(0, 0, 1, 1, gl.RGBA, gl.FLOAT, values);
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
return Array.from(values);
};The examples in Sections 3.2 and Statements and Built-ins run in a page that loads the helper and defines gl as a WebGL 2 context.