{"id":24529728,"url":"https://github.com/learosema/glea","last_synced_at":"2025-04-14T17:32:38.675Z","repository":{"id":40773158,"uuid":"197945583","full_name":"learosema/glea","owner":"learosema","description":"Minimal footprint WebGL library","archived":false,"fork":false,"pushed_at":"2023-01-06T04:34:27.000Z","size":1760,"stargazers_count":44,"open_issues_count":21,"forks_count":3,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-17T00:41:59.997Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/learosema.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2019-07-20T15:04:14.000Z","updated_at":"2024-10-16T09:43:51.000Z","dependencies_parsed_at":"2023-02-05T08:02:30.399Z","dependency_job_id":null,"html_url":"https://github.com/learosema/glea","commit_stats":null,"previous_names":["terabaud/glea"],"tags_count":6,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/learosema%2Fglea","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/learosema%2Fglea/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/learosema%2Fglea/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/learosema%2Fglea/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/learosema","download_url":"https://codeload.github.com/learosema/glea/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":235082228,"owners_count":18932920,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-22T07:52:18.894Z","updated_at":"2025-01-22T07:52:19.588Z","avatar_url":"https://github.com/learosema.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# GLea - GL experience artistry\n\nGLea is a low-level WebGL library with a minimal footprint.\nIt provides helper functions for creating a WebGL program, compiling shaders and passing data from JavaScript to the shader language.\n\n## Introduction\n\nThere are several options to embed GLea into your project. You can load GLea directly via script tag:\n\n```html\n\u003cscript src=\"https://unpkg.com/glea@latest/dist/glea.umd.min.js\"\u003e\u003c/script\u003e\n```\n\nInside a JavaScript ES module:\n\n```js\nimport GLea from 'https://cdn.skypack.dev/glea';\n```\n\nOr via NPM, you can install GLea via `npm i glea` and import it like this:\n\n```js\nimport GLea from 'glea';\n```\n\n### Initialization\n\nBy 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.\n\nIf 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.\n\nThe GLea instance expects a shaders property, containing your fragment and vertex shader.\nAlso, a buffers property, which contains the data that is passed as attributes to the vertex shader.\n\nIf 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.\n\n### Setting uniforms\n\nGLea provides several helper functions to set uniforms to pass data from JavaScript to GLSL. These are:\n\n```js\n// set uniform float\nglea.uni('pi', Math.PI);\n\n// set uniform int\nglea.uniI('width', innerWidth);\n\n// set uniform float vector (supported types are vec2, vec3, vec4)\nglea.uniV('vector', [Math.sqrt(2), Math.sqrt(3)]);\n\n// set uniform int vector\nglea.uniIV('resolution', [innerWidth, innerHeight]);\n\n// set uniform matrix\n// HEADS UP: it is the other way round as you would write it down on paper\n// prettier-ignore\nglea.uniM('translateMatrix', [\n  1, 0, 0, 0, // column 1\n  0, 1, 0, 0, // column 2\n  0, 0, 1, 0, // column 3\n  x, y, z, 1, // column 4\n]);\n```\n\n### Draw\n\nGLea provides a wrapper to [drawArrays](https://developer.mozilla.org/en-US/docs/Web/API/WebGLRenderingContext/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\nautomatically from the buffers.\n\n```js\nconst { gl } = glea;\n\nglea.drawArrays(gl.TRIANGLE_STRIP);\n\n// The same as:\nconst numVertices = 4;\nglea.gl.drawArrays(gl.TRIANGLE_STRIP, 0, numVertices);\n```\n\n### Multiple programs and switching\n\nGLea supports multiple programs.\n\n```js\nconst prg1 = new GLea({\n  shaders: [GLea.vertexShader(vert), GLea.fragmentShader(frag)],\n}).create();\n\nconst prg2 = prg1.add({\n  shaders: [GLea.vertexShader(vert2), GLea.fragmentShader(frag2)],\n  buffers: {\n    position: GLea.buffer(3, Ella.Geometry.sphere(0.25, 32, 16).toTriangles()),\n  },\n});\n```\n\nThe the main instance `prg1` and its child `prg2` use the same underlying WebGLRenderingContext.\nIn the example `prg1` renders a plane geometry (GLea provides a `position` attribute with a plane geometry by default),\nand `prg2` provides a sphere geometry. The sphere geometry is provided by [ella-math](https://github.com/terabaud/ella-math).\n\nIn the draw loop, the switching between programs is done via `enableAttribs` and `disableAttribs`:\n\n```js\n// Shader 1 does the background animation\nprg1.gl.disable(gl.DEPTH_TEST);\nprg1.enableAttribs();\nprg1.uniV('resolution', [width, height]);\nprg1.uni('time', time * 1e-3);\nprg1.drawArrays(gl.TRIANGLE_STRIP);\nprg1.disableAttribs();\n\n// Shader 2 renders a sphere\ngl.enable(gl.DEPTH_TEST);\nprg2.enableAttribs();\nprg2.uniV('resolution', [width, height]);\nprg2.uni('time', time * 1e-3);\nprg2.uniM('uPM', this.projectionMat.toArray());\nprg2.uniM('uVM', this.viewMat.toArray());\nprg2.drawArrays(gl.TRIANGLES);\nprg2.disableAttribs();\n```\n\n[Full example](https://codepen.io/terabaud/pen/wvMQQyr)\n\n### Loading textures\n\nI'm using a loadImage helper function that wraps `img.onload` into a Promise:\n\n```js\nfunction loadImage(url) {\n  return new Promise((resolve, reject) =\u003e {\n    const img = new Image();\n    img.crossOrigin = 'Anonymous';\n    img.src = url;\n    img.onload = () =\u003e {\n      resolve(img);\n    };\n    img.onerror = () =\u003e {\n      reject(img);\n    };\n  });\n}\n\nasync function setup() {\n  const img = await loadImage('https://placekitten.com/256/256/');\n  const textureIndex = 0;\n  glea.createTexture(textureIndex);\n  glea.gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, img);\n  glea.uniI('texture0', textureIndex);\n}\n\nsetup();\n```\n\nIn GLSL, you can access the texture like this:\n\n```glsl\nuniform sampler2D texture0;\n\nvoid main() {\n  vec2 coord = 1.0 - gl_FragCoord.xy / vec2(width, height);\n  gl_FragColor = texture2D(texture1, coord);\n}\n```\n\n## Example\n\n```js\nimport GLea from 'https://cdn.skypack.dev/glea';\n\nconst vert = `\nprecision highp float;\nattribute vec2 position;\n\nvoid main() {\n  gl_Position = vec4(position, 0, 1.0);\n}\n`;\n\nconst frag = `\nprecision highp float;\nuniform float time;\nuniform vec2 resolution;\n\nvoid main() {\n  float vmin = min(resolution.y, resolution.x);\n  vec2 p = (gl_FragCoord.xy - .5 * resolution) / vmin;\n  float r = .5 + .5 * sin(5. * log(length(p)) - time * 1.2);\n  float g = .5 + .5 * sin(5. * log(length(p)) + sin(time + 2. * p.x));  \n  float b = .5 + .5 * sin(.2 + 5. * log(length(p)) + sin(time * .4 + 4. * p.y));\n  gl_FragColor = vec4(r, g, b, 1.);\n}\n`;\n\nconst glea = new GLea({\n  shaders: [GLea.fragmentShader(frag), GLea.vertexShader(vert)],\n  buffers: {\n    // create a position attribute bound\n    // to a buffer with 4 2D coordinates\n    // this is what GLea provides by default if you omit buffers in the constructor\n    position: GLea.buffer(2, [1, 1, -1, 1, 1, -1, -1, -1]),\n  },\n}).create();\n\nfunction loop(time) {\n  const { gl, width, height } = glea;\n  glea.clear();\n  glea.uniV('resolution', [width, height]);\n  glea.uni('time', time * 1e-3);\n  gl.drawArrays(gl.TRIANGLE_STRIP, 0, 4);\n  requestAnimationFrame(loop);\n}\n\nfunction setup() {\n  const { gl } = glea;\n  window.addEventListener('resize', () =\u003e {\n    glea.resize();\n  });\n  loop(0);\n}\n\nsetup();\n```\n\n- [Try this on Codepen](https://codepen.io/terabaud/pen/PoPJqvM)\n\n## Exampes\n\n- [Example 01: Triangle](https://codepen.io/terabaud/pen/OKVpYV)\n- [Example 02: Full screen plane](https://codepen.io/terabaud/pen/eqNjjY)\n- [Example 03: Cube](https://codepen.io/terabaud/pen/EqgpbQ)\n- [Example 04: Circle Heart Morph](https://codepen.io/terabaud/pen/BaNRbXL)\n- [Example 05: Rotating heart yin yang morph pattern](https://codepen.io/terabaud/pen/VwLbVjE)\n- [Example 06: Fun with circles](https://codepen.io/terabaud/pen/xxGdeEe)\n- [Example 07: Retro Style Dither Cam](https://codepen.io/terabaud/pen/WNvoOgK)\n- [Example 08: Signed Distance Field Symmetric Diff](https://codepen.io/terabaud/pen/dyoXjVv)\n- [Example 09: Hypnotizing Cyclone 2.0](https://codepen.io/terabaud/pen/PowKxNp)\n- [Example 10: Hypnotizing Cyclone 3.0](https://codepen.io/terabaud/pen/bGNMGvb)\n- [Example 11: numeric spiral](https://codepen.io/terabaud/pen/poogqxq)\n- [Example 12: Evil virus](https://codepen.io/terabaud/pen/ZgreLo)\n- [Example 13: Halftone Circles](https://codepen.io/terabaud/pen/BajJbgd)\n\n### More examples\n\n- There is more: https://terabaud.github.io/hello-webgl/\n\n## Additional WebGL resources\n\n- [WebGL Fundamentals](https://webglfundamentals.org/)\n- [WebGL 2 Fundamentals](https://webgl2fundamentals.org/)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flearosema%2Fglea","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Flearosema%2Fglea","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Flearosema%2Fglea/lists"}