{"id":14356549,"url":"https://github.com/elm-explorations/webgl","last_synced_at":"2026-02-21T06:30:55.658Z","repository":{"id":54594864,"uuid":"131859674","full_name":"elm-explorations/webgl","owner":"elm-explorations","description":"Functional rendering with WebGL in Elm","archived":false,"fork":false,"pushed_at":"2021-02-08T19:35:37.000Z","size":707,"stargazers_count":117,"open_issues_count":13,"forks_count":17,"subscribers_count":7,"default_branch":"main","last_synced_at":"2024-12-20T00:33:34.284Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"https://package.elm-lang.org/packages/elm-explorations/webgl/latest/","language":"Elm","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/elm-explorations.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-05-02T14:05:42.000Z","updated_at":"2024-11-04T21:42:16.000Z","dependencies_parsed_at":"2022-08-13T20:40:48.706Z","dependency_job_id":null,"html_url":"https://github.com/elm-explorations/webgl","commit_stats":null,"previous_names":[],"tags_count":11,"template":false,"template_full_name":null,"purl":"pkg:github/elm-explorations/webgl","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elm-explorations%2Fwebgl","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elm-explorations%2Fwebgl/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elm-explorations%2Fwebgl/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elm-explorations%2Fwebgl/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/elm-explorations","download_url":"https://codeload.github.com/elm-explorations/webgl/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/elm-explorations%2Fwebgl/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29675413,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-21T06:23:40.028Z","status":"ssl_error","status_checked_at":"2026-02-21T06:23:39.222Z","response_time":107,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"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":"2024-08-27T10:01:21.214Z","updated_at":"2026-02-21T06:30:55.628Z","avatar_url":"https://github.com/elm-explorations.png","language":"Elm","funding_links":[],"categories":["Elm"],"sub_categories":[],"readme":"# WebGL for Elm\n\n[A simple API](https://package.elm-lang.org/packages/elm-explorations/webgl/latest/WebGL)\nfor rendering with WebGL. This is useful for both 2D and 3D\nrendering because it lets you take advantage of hardware acceleration with the\nGPU, meaning you can render things more quickly.\n\n[Here are some examples](https://github.com/elm-explorations/webgl/tree/main/examples) so you can get a feel for the API, but make sure you\nread on to learn how WebGL and the GPU really work!\n\n[![Triangle](https://elm-explorations.github.io/webgl/examples/screenshots/triangle.jpg)](https://elm-explorations.github.io/webgl/examples/triangle.html)\n[![Cube](https://elm-explorations.github.io/webgl/examples/screenshots/cube.jpg)](https://elm-explorations.github.io/webgl/examples/cube.html)\n[![Crate](https://elm-explorations.github.io/webgl/examples/screenshots/crate.jpg)](https://elm-explorations.github.io/webgl/examples/crate.html)\n[![Thwomp](https://elm-explorations.github.io/webgl/examples/screenshots/thwomp.jpg)](https://elm-explorations.github.io/webgl/examples/thwomp.html)\n[![FirstPerson](https://elm-explorations.github.io/webgl/examples/screenshots/first-person.jpg)](https://elm-explorations.github.io/webgl/examples/first-person.html)\n\n## Understanding WebGL\n\nTo get the most out of this library and out of the GPU, it is best to pair some\nexamples with a fairly solid understanding of how information flows through the\nrendering pipeline. This section gives a high-level overview of the pipeline\nand the corresponding terminology.\n\nAt a high-level, there are two general concepts to understand: meshes and\nshaders. The details of each of these are crucial to using WebGL effectively.\n\n### Meshes\n\nA mesh is all about triangles. By placing small triangles side-by-side, you can\nbuild up larger 3D shapes. We define each triangle by associating a bunch of\nattributes\u0026mdash;like position and color\u0026mdash;with each corner of the triangle.\n\nWe create and update our meshes on the CPU, so working with a model does not get\nany direct benefits from the GPU. Meshes are sent from the CPU to the GPU to be\nrendered. This transfer can be quite expensive, so it is best to try to avoid\ncreating new meshes.\n\nSome tricks to minimize this include breaking a mesh up into many smaller\npieces that can be transformed independently. For example, if you want to\nrender a skeleton, each bone could be a separate mesh, so rather than send\na new version of the entire skeleton on every frame, you just send a\ntransformation for each bone.\n\n### Shaders\n\nA [shader](https://en.wikipedia.org/wiki/Shader) is all turning meshes into\npictures. A shader is a program that runs on the GPU, so it benefits from\nlots of parallelization. As a general rule, you want to be doing computation\nhere rather than on the CPU if possible.\n\nIn Elm, shaders are defined with a language called\n[GLSL](https://en.wikipedia.org/wiki/OpenGL_Shading_Language). These are programs\nthat take in small high-level values and do a bunch of rendering based on that.\nFor example, you can send over a matrix that represents where the camera should\nbe and all of the meshes loaded onto the GPU will be transformed accordingly.\n\n### Combining Meshes and Shaders\n\nThe following diagram illustrates the entire pipeline. Keep reading past the\ndiagram, all the terms will be explained!\n\n![WebGL Pipeline](https://raw.githubusercontent.com/elm-explorations/webgl/main/pipeline.png)\n\nWe start with a mesh. It's a bunch of raw data points that we want to render on\nscreen. From there, the data flows through two types of shaders:\n\n- [**Vertex Shaders**](https://en.wikipedia.org/wiki/Shader#Vertex_shaders) \u0026mdash;\n  Our mesh is made up of lots of triangles. Each corner of a triangle is called a\n  _vertex_. The vertex shader has access to all of the attributes of each vertex,\n  like position and color, letting us move triangles around or change their color.\n\n- [**Fragment Shaders**](https://en.wikipedia.org/wiki/Shader#Pixel_shaders) \u0026mdash;\n  Also known as pixel shaders, these shaders are like filters on individual\n  pixels. They let you work with pixels to add lighting effects or add\n  postprocessing effects like blur or edge-detection.\n\nThe flow of data between the CPU and each of our shaders is very well defined.\nTo send information, there are three kinds of specialized variables:\n\n- **Uniform** \u0026mdash; these are global read-only variables that can be used\n  in both the vertex and fragment shaders. They are defined on the CPU.\n\n- **Attribute** \u0026mdash; these variables represent a particular vertex in our\n  mesh. The vertex shader takes in these variables to compute some\n  transformations on each vertex.\n\n- **Varying** \u0026mdash; these are variables you can write in the vertex shader\n  which then get passed along into the fragment shader, where they are\n  read-only. This lets you pass information along as you compute things in\n  your rendering pipeline.\n\n## Making the most of the GPU\n\nA typical mesh may be quite large, with hundreds or thousands of vertices, each\nwith a potentially large set of attributes. Working with a mesh on the CPU is\nexpensive for two major reasons:\n\n1. The CPU is sequential, so you must work on each vertex one at a time.\n   On the GPU, you can work with tons of vertices in parallel with a Vertex\n   Shader, making things much faster.\n\n2. Transfering data from CPU to GPU is expensive. Ideally you want to transfer\n   all of the vertices once and make any updates to the mesh by passing in\n   uniform variables to the Vertex Shader. Not only is it cheaper to send a\n   couple matrices to the GPU, but once they get there, the GPU can use them\n   in parallel.\n\nThis library facilitates this by caching known meshes on the GPU. If you create\na mesh and use it many times, it only gets transfered to the GPU once. Now if\nyou update that mesh, the new version will need to be loaded onto the GPU\nseparately. That means it is best to create a fairly general mesh and modify it\nwith uniform variables in a Vertex Shader.\n\n## Writing Shaders\n\nShaders are written in a language called\n[GLSL](https://en.wikipedia.org/wiki/OpenGL_Shading_Language). This is a widely\nused language for shaders with [websites](https://www.shadertoy.com) devoted\nto sharing creative demos, so you will often be able to use that shader\ncode directly in Elm. A basic vertex shader could be defined like this:\n\n```elm\nvertexShader : Shader { position:Vec3, coord:Vec3 } { u | view:Mat4 } { vcoord:Vec2 }\nvertexShader = [glsl|\n\nattribute vec3 position;\nattribute vec3 coord;\nuniform   mat4 view;\nvarying   vec2 vcoord;\n\nvoid main () {\n  gl_Position = view * vec4(position, 1.0);\n  vcoord = coord.xy;\n}\n\n|]\n```\n\nWithin the `[glsl| ... |]` block, you just write plain GLSL. Elm is actually\naware of the types of the attributes, uniforms, and varyings coming in and out\nof the shader, so the shader block is given a type that enforces this API. The\ntype of `vertexShader` says that we have two attributes named `position` and\n`coord`, one uniform named `view`, and one varying called `vcoord`. This means\nElm's type checker can make sure you are using the shader in a meaningful way,\navoiding a totally blank screen that can happen if your shader has an error in\nit.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felm-explorations%2Fwebgl","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felm-explorations%2Fwebgl","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felm-explorations%2Fwebgl/lists"}