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

gleasy

v0.0.9

Published

WebGL2 helper library

Readme

gleasy

A lightweight (4.0kb) wrapper over webgl2, with no dependenices.

You'll need to know WebGL concepts, but won't have to think about binding attribute pointers and uniforms. The main primitives are designed to be as flexible as possible, while abstracting away a lot of the boilerplate.


Shader

Create a shader with automatic uniform setters:

In your vertex shader:

#version 300 es
uniform mat3 uTransformMatrix;
uniform vec3 uPos;
void main() { 
   gl_Position = vec4(uTransformMatrix * uPos, 1.)
}

In your program:

import { Shader } from 'gleasy'

// describe uniforms to get type hints
type Uniforms = { 
   uTransformMatrix: 'mat3'
   uPos: 'vec3'
}

// set initial values
const shader = new Shader<Uniforms>(gl, vertexSrc, fragmentSrc, {
   uPos: [0, 0, 0],
   uTransformMatrix: [...matrix]
})

// update uniform values later
shader.uniforms.uTransformMatrix = [...transformedMatrix]

// before the draw call
shader.use()

Uniform types

All gl2 uniform types are supported: float vec2 vec3 vec4 int ivec2 ivec3 ivec4 uint uvec2 uvec3 uvec4 bool bvec2 bvec3 bvec4 mat2 mat3 mat4 mat2x3 mat2x4 mat3x2 mat3x4 mat4x2 mat4x3 sampler2D samplerCube

And work with specified lengths for arrays: float[3], vec3[6]

Or arrays of unspecified length: float[]

Example glsl:

#version 300 es
uniform float uTime;
uniform vec2 uPos;
uniform vec3 uColor;
uniform mat3 uMatrix;
uniform sampler2D uTex;
uniform samplerCube uCubeMap;
uniform vec3 uLightColors[4];
...

Types:

type Uniforms { 
   uTime: 'float'
   uPos: 'vec2'
   uColor: 'vec3' 
   uMatrix: 'mat3'
   uTex: 'sampler2D'
   uCubeMap: 'samplerCube'
   uLightColors: 'vec3[4]' 
   ...
}

const shader = new Shader<Uniforms>(gl, vertex, fragment, {
   uLightColors // number[12]
})

VertexBuffer

Vertex data can be interleaved, or be spread across multiple buffers. You can pass a TypedArray directly, or it will default to a Float32Array when called with a standard array type:

import { VertexBuffer } from 'gleasy'

// interleaved
const vertices = new VertexBuffer(gl, new Float32Array([
   // x,y,z         // r,g,b
   0.0,  0.5, 0.0,  1.0, 0.0, 0.0, 
  -0.5, -0.5, 0.0,  0.0, 1.0, 0.0, 
   0.5, -0.5, 0.0,  0.0, 0.0, 1.0 
]))

// multiple buffers
const position = new VertexBuffer(gl, [
   0.0,  0.5, 0.0,  
  -0.5, -0.5, 0.0,  
   0.5, -0.5, 0.0,  
])
const color = new VertexBuffer(gl, [
   1.0, 0.0, 0.0,
   0.0, 1.0, 0.0, 
   0.0, 0.0, 1.0 
])

// uses unsigned ints with Uint8Array
const vertexId = new VertexBuffer(gl, new Uint8Array([
   0, 0, 0,
   1, 1, 1, 
   2, 2, 2 
]))

You can pass in other typed arrays to the constructor: Int8Array, Int16Array, Int32Array, Uint8Array, Uint16Array, Uint32Array, Uint8ClampedArray.

These can generally be used for integer types in your shader (uint, int, uvec3, ivec3, etc).

VAO / Vertex array objects

Get attribute names/locations from the shader program:

import { Shader, VAO } from 'gleasy'

const vertices = new VertexBuffer(gl, array)
const shader = new Shader(gl, vertex, fragment)

// describe the vertex attribute layout on 
// the VAO for automatic attribute binding
const vao = new VAO(gl, shader, {
   buffer: vertices,
   layout: { 
      aPosition: { type: 'vec3' }, 
      aColor: { type:'vec3' }
   }
})

// draw
shader.use()
vao.bind()
vao.draw()

You can use separate buffers or manually specify attribute locations for better flexibility:

// set a separate buffer for each attribute:
const vao = new VAO(gl, shader, {
   layout: { 
      aPosition: { type: 'vec3', buffer: position }, 
      aColor: { type:'vec3', buffer: color }
   }
})

// and/or use location indexes (don't pass a shader):
const vao = new VAO(gl, {
   buffer: position, // default buffer
   layout: [
      { type: 'vec3', location: 0 }, // position buffer at location 0
      { type: 'vec3', location: 1, buffer: color } // color buffer at location 1
   ]
})

// draw
shader.use()
vao.bind()
vao.draw()

Vertex attribute layouts

Attribute layouts can also be described directly on the VertexBuffer and used in draw calls directly, if you really want.

In your vertex shader:

layout(location=0) in vec3 aPosition;
layout(location=1) in vec3 aColor;

In your program:

const vertices = new VertexBuffer(gl, array)

// describe the vertex attribute layout
vertices.setLayout([
   { type: 'vec3', location: 0 },
   { type: 'vec3', location: 1 },
])

// create and use a shader
shader.use()

// draw directly from attribute locations
vertices.bind()
// explicit call to bindLayout() as it involves 
// some overhead when compared to VAOs
vertices.bindLayout()
vertices.draw()

VertexIndex

Draw parts of your vertex buffers:

import { VertexIndex, VertexBuffer } from 'gleasy'

// create a vertex buffer
const vertices = new VertexBuffer(gl, array)

// create your index, only draws the first 3 vertices (0, 1, 2)
const index = new VertexIndex(gl, new Uint16Array([0, 1, 2]))

shader.use()
index.bind() 
index.draw()

You can also explicitly pass in other typed arrays to the constructor: Uint8Array, Uint16Array, Uint32Array, Uint8ClampedArray.

A standard array type will default to a 16-bit unsigned int array (Uint16Array).

The index can also be saved in a VAO:

const vao = new VAO(gl, {
   index, // include an index
   buffer,
   layout: {
      aPos: { type: 'vec3' }, 
   }
})

// only need to bind the vao
vao.bind()
index.draw()

Texture

Create a texture from an image:

import { Texture } from 'gleasy'
// create a texture from an image 
// (making sure the image has already loaded)
const texture = new Texture(gl, image, {
   flip:true, // flip vertical        
})

// bind to texture location 0
texture.bind(0)

// set texture location in uniform
type Uniforms = { tex: 'sampler2D' }
const shader = new Shader<Uniforms>(gl, vertex, fragment, { tex:0 })

shader.use()
vao.bind()
vao.draw()

Texture options:

| Option | Default | Description | |--------|---------|-------------| | flip | false | Flip the image vertically | | repeat | false | Repeat sampling | | repeatMirror | false | Repeat sampling but mirrored | | mipmaps | false | Generate and use mipmaps | | interpolate | true | Interpolate (nearest-neighbour filtering) | | interpolateMips | true | Interpolate between mipmap levels |

Sampler usage:

In fragment shader:

#version 300 es
precision highp float;
uniform sampler2D tex;
in vec2 uv;
out vec4 fragColor;

void main() {
   fragColor = texture(tex, uv);
}

Multi-pass rendering using FrameBuffer

import { Texture, FrameBuffer } from 'gleasy'
// create a texture to use use as the framebuffer
const texture = new Texture(gl)
const frame = new FrameBuffer(gl, texture)

// render first pass into framebuffer
shader.use()
frame.bind() 
vao.draw()

// unbind frame, render to canvas element
frame.unbind()

// render second pass, samping the framebuffer texture
shader2.use()
texture.bind(0)
quad.draw() 

Helpers

The GL viewport should match the canvas, set this with:

import { setGLViewport } from 'gleasy'
const gl = canvas.getContext('webgl2')
setGLViewport(gl, canvas)