npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

glea

v1.3.1

Published

GL experience artistry

Downloads

168

Readme

GLea - GL experience artistry

GLea is a low-level WebGL library with a minimal footprint. It provides helper functions for creating a WebGL program, compiling shaders and passing data from JavaScript to the shader language.

Introduction

There are several options to embed GLea into your project. You can load GLea directly via script tag:

<script src="https://unpkg.com/glea@latest/dist/glea.umd.min.js"></script>

Inside a JavaScript ES module:

import GLea from 'https://cdn.skypack.dev/glea';

Or via NPM, you can install GLea via npm i glea and import it like this:

import GLea from 'glea';

Initialization

By default, GLea looks for a canvas element in your HTML and uses that. If there is no canvas element existing, GLea creates one for you.

If your HTML document doesn't include any CSS (neither a style nor a link tag, a minimal stylesheet is provided that sizes the canvas to the browser's viewport size.

The GLea instance expects a shaders property, containing your fragment and vertex shader. Also, a buffers property, which contains the data that is passed as attributes to the vertex shader.

If no buffers are provided, GLea provides a default position attribute with a buffer containing 4 vec2 values for a triangle strip, defining a plane filling the screen.

Setting uniforms

GLea provides several helper functions to set uniforms to pass data from JavaScript to GLSL. These are:

// set uniform float
glea.uni('pi', Math.PI);

// set uniform int
glea.uniI('width', innerWidth);

// set uniform float vector (supported types are vec2, vec3, vec4)
glea.uniV('vector', [Math.sqrt(2), Math.sqrt(3)]);

// set uniform int vector
glea.uniIV('resolution', [innerWidth, innerHeight]);

// set uniform matrix
// HEADS UP: it is the other way round as you would write it down on paper
// prettier-ignore
glea.uniM('translateMatrix', [
  1, 0, 0, 0, // column 1
  0, 1, 0, 0, // column 2
  0, 0, 1, 0, // column 3
  x, y, z, 1, // column 4
]);

Draw

GLea provides a wrapper to drawArrays from the underlying WebGLRenderingContext. It works exactly like the original drawArrays function, but if you don't provide any vertex count, it is determined automatically from the buffers.

const { gl } = glea;

glea.drawArrays(gl.TRIANGLE_STRIP);

// The same as:
const numVertices = 4;
glea.gl.drawArrays(gl.TRIANGLE_STRIP, 0, numVertices);

Multiple programs and switching

GLea supports multiple programs.

const prg1 = new GLea({
  shaders: [GLea.vertexShader(vert), GLea.fragmentShader(frag)],
}).create();

const prg2 = prg1.add({
  shaders: [GLea.vertexShader(vert2), GLea.fragmentShader(frag2)],
  buffers: {
    position: GLea.buffer(3, Ella.Geometry.sphere(0.25, 32, 16).toTriangles()),
  },
});

The the main instance prg1 and its child prg2 use the same underlying WebGLRenderingContext. In the example prg1 renders a plane geometry (GLea provides a position attribute with a plane geometry by default), and prg2 provides a sphere geometry. The sphere geometry is provided by ella-math.

In the draw loop, the switching between programs is done via enableAttribs and disableAttribs:

// Shader 1 does the background animation
prg1.gl.disable(gl.DEPTH_TEST);
prg1.enableAttribs();
prg1.uniV('resolution', [width, height]);
prg1.uni('time', time * 1e-3);
prg1.drawArrays(gl.TRIANGLE_STRIP);
prg1.disableAttribs();

// Shader 2 renders a sphere
gl.enable(gl.DEPTH_TEST);
prg2.enableAttribs();
prg2.uniV('resolution', [width, height]);
prg2.uni('time', time * 1e-3);
prg2.uniM('uPM', this.projectionMat.toArray());
prg2.uniM('uVM', this.viewMat.toArray());
prg2.drawArrays(gl.TRIANGLES);
prg2.disableAttribs();

Full example

Loading textures

I'm using a loadImage helper function that wraps img.onload into a Promise:

function loadImage(url) {
  return new Promise((resolve, reject) => {
    const img = new Image();
    img.crossOrigin = 'Anonymous';
    img.src = url;
    img.onload = () => {
      resolve(img);
    };
    img.onerror = () => {
      reject(img);
    };
  });
}

async function setup() {
  const img = await loadImage('https://placekitten.com/256/256/');
  const textureIndex = 0;
  glea.createTexture(textureIndex);
  glea.gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);
  glea.uniI('texture0', textureIndex);
}

setup();

In GLSL, you can access the texture like this:

uniform sampler2D texture0;

void main() {
  vec2 coord = 1.0 - gl_FragCoord.xy / vec2(width, height);
  gl_FragColor = texture2D(texture1, coord);
}

Example

import GLea from 'https://cdn.skypack.dev/glea';

const vert = `
precision highp float;
attribute vec2 position;

void main() {
  gl_Position = vec4(position, 0, 1.0);
}
`;

const frag = `
precision highp float;
uniform float time;
uniform vec2 resolution;

void main() {
  float vmin = min(resolution.y, resolution.x);
  vec2 p = (gl_FragCoord.xy - .5 * resolution) / vmin;
  float r = .5 + .5 * sin(5. * log(length(p)) - time * 1.2);
  float g = .5 + .5 * sin(5. * log(length(p)) + sin(time + 2. * p.x));  
  float b = .5 + .5 * sin(.2 + 5. * log(length(p)) + sin(time * .4 + 4. * p.y));
  gl_FragColor = vec4(r, g, b, 1.);
}
`;

const glea = new GLea({
  shaders: [GLea.fragmentShader(frag), GLea.vertexShader(vert)],
  buffers: {
    // create a position attribute bound
    // to a buffer with 4 2D coordinates
    // this is what GLea provides by default if you omit buffers in the constructor
    position: GLea.buffer(2, [1, 1, -1, 1, 1, -1, -1, -1]),
  },
}).create();

function loop(time) {
  const { gl, width, height } = glea;
  glea.clear();
  glea.uniV('resolution', [width, height]);
  glea.uni('time', time * 1e-3);
  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);
  requestAnimationFrame(loop);
}

function setup() {
  const { gl } = glea;
  window.addEventListener('resize', () => {
    glea.resize();
  });
  loop(0);
}

setup();

Exampes

More examples

  • There is more: https://terabaud.github.io/hello-webgl/

Additional WebGL resources