Lygia declares bundle entry points its publish step skips
LYGIA, it's a granular and multi-language (GLSL, HLSL, Metal, WGSL, WEGL and CUDA) shader library designed for performance and flexibility
At a glance
- What is it?
- A granular shader library spread across GLSL, HLSL, Metal, WGSL and CUDA files, where the npm metadata names a Prosperity and Patron license, the summary sentence says WEGL while the files say WESL, and the publish script builds only one of the two bundles.
- Who is it for?
- Lygia suits a graphics programmer who wants one function rather than a framework, since the include style and prune.py make it cheap to vendor a single language. Two things are worth settling first.
- Can I use it commercially?
- Check first. The repository uses a licence we do not classify automatically, so read its LICENSE file before any commercial use.
- Is it still maintained?
- Yes. The repository last received commits 21 days ago.
- What is it written in?
- Mainly GLSL, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on November 14, 2026, and from our analysis. They are not legal advice.
Star history
- patriciogonzalezvivo/lygia3,489 ★ · +42
| Repository | 2026-09-24 | 2026-11-14 |
|---|---|---|
| patriciogonzalezvivo/lygia | 3.4k | 3.5k |
42 Stars in the last 51 days, measured from the daily GitHub snapshot. Compare with other projects
Editorial analysis
The license field names no standard license
The npm manifest is explicit about this. Its license field reads `Prosperity License & Patron License (https://lygia.xyz/license)`, which is a pair of named documents rather than one of the licenses a package index recognises. Alongside it, the repository's own license metadata reports NOASSERTION, and the tree carries a `LICENSE.md` at the root. Three places answer the license question and none of them names the same thing. The README, meanwhile, opens by calling LYGIA the biggest shader library, battle proof and cross platform, and says it grows and improves every day thanks to community support, without a figure behind any of that. What the package actually is, a set of reusable shader functions you include individually, is easy to verify from the tree.
The declared entry points come from the build publishing never runs
`package.json` points four fields at webpack output: `main`, `unpkg` and `jsdelivr` all resolve to `dist/umd/lygia.main.js`, and `module` resolves to `dist/module/lygia.main.js`. The script that produces those paths is `build`, which is `rm -rf dist/* && webpack`. The publish hook is `prepublishOnly`, and it is `pnpm build:wesl`, nothing else. `build:wesl` is a different tool, `wesl-packager --multiBundle --outDir dist`. So the bundle layout that a consumer's bundler will follow is generated by the one script the publish step does not invoke, and the artifact the publish step does build is the WESL multi bundle. The same split shows up in testing, where `test:built` runs only after `build:wesl` and sets `TEST_BUNDLES=true`.
The summary sentence says WEGL and the files say WESL
The one line summary calls LYGIA a multi language library for GLSL, HLSL, Metal, WEGL and CUDA. The repository spells the fifth one differently. There is `README_WESL.md`, a `wesl.toml` at the root, a flat aggregator named `version.wesl`, a script called `build:wesl`, and WESL among the package keywords. Nothing in the tree carries the WEGL spelling. Language specific READMEs exist for GLSL, Metal, WESL and WebGPU, four in total, and there is no README for HLSL even though flat HLSL files sit at the root alongside the GLSL, MSL, WGSL and CUH ones. Five root level aggregators repeat the same base names across languages: `math`, `sampler`, `sdf`, `version` and `sample`, which is how a caller pulls a whole category instead of one function.
Most sample functions ship in three languages, not five
The `sample/` directory shows how even coverage is across the claimed language set. Nine functions are visible. `2DCube`, `3DSdf`, `bicubic`, `bracketing`, `bumpMap` and `derivative` each have a `.glsl`, a `.hlsl` and a `.wgsl` file and no Metal variant. `dither` has `.glsl` and `.wgsl` with no HLSL. `dof` appears as a single `.glsl`. `clamp2edge` is the only one of the nine carrying a `.msl` next to its other three. Metal is declared as a target language and has root level `math.msl`, `sampler.msl` and `sdf.msl` files, so the gap is in the samples rather than in the library, but it means the count of functions you can read in Metal is smaller than the language list suggests.
The snapshot script commits and pushes straight to main
Image snapshot updates are handled by a script named `snapshot:push`. It changes into `test/wesl/__image_snapshots__`, stages everything with `git add -A`, then runs `git diff --cached --quiet || git commit -m 'update snapshots'` and finishes with `git push origin HEAD:main`. Three things follow from that one line. Snapshots are pushed directly to `main` rather than to a review branch. The staging is unconditional, so whatever sits in that directory goes with them. And the shell operators are ungrouped, so the commit and the push are chained to whatever the diff check returns rather than to each other. The snapshot directory is versioned, which is the point, but the path to updating it bypasses the branch flow.
Deno and native test paths exist outside the CI entry point
The scripts block carries more test routes than the check that CI calls. `ci:check` is `pnpm test:once && pnpm test:built`. `test:once` is `pnpm vitest run && wgsl-test run`. Beyond those sit `test:deno:vitest` as `deno run -A --unstable-webgpu npm:vitest run`, `test:deno:native` as `deno run -A --unstable-webgpu npm:wgsl-test run`, and `test:native` as `wgsl-test run` on its own. So the same suites can be driven under Deno with WebGPU enabled, or through a native runner, and none of those routes is part of `ci:check`. The Deno invocations also run with full permissions, the `-A` flag, which is what lets the WebGPU unstable flag through.
The lint script calls ESLint and the root ships a Biome config
`lint` is defined as `eslint --fix --ext .js .`, which fixes in place rather than only reporting. At the top level of the tree, though, the configuration files that are present are `biome.jsonc`, `tsconfig.json` and `vitest.config.ts`, and no ESLint configuration file sits beside them. There is also `webpack.config.js` alongside `pnpm-lock.yaml` and `pnpm-workspace.yaml`, so the package manager is pnpm while the JavaScript bundling is webpack and the test runner is vitest, with three separate toolchains configured in a repository whose source is mostly shader files. `.npmignore` is present for the published package, and the flat aggregator files mean a caller usually includes one file rather than an entry point.
Four install routes, and a resolver commented out in place
Getting the library locally is a choice of four routes. A plain clone brings the history with it.
git clone https://github.com/patriciogonzalezvivo/lygia.gitA submodule files it inside your own history instead.
git submodule add https://github.com/patriciogonzalezvivo/lygia.git`npx degit` skips the history entirely, which the page says reduces the project size by 9MB or more.
npx degit https://github.com/patriciogonzalezvivo/lygia.git lygiaAnd `prune.py` cuts the library down to a single language.
python prune.py --all --keep glslA fifth route is the server, a script tag for `https://lygia.xyz/resolve.js` or `resolve.esm.js`. That resolver is the feature the README already switches off: a block offering to resolve a shader's dependencies by dragging the file into a box on the page sits inside an HTML comment, so neither the offer nor the box renders. The examples link on the same page points at `https:lygia.xyz/examples`, missing the double slash after the scheme.
Editorial conclusion
Lygia suits a graphics programmer who wants one function rather than a framework, since the include style and prune.py make it cheap to vendor a single language. Two things are worth settling first. The license field names Prosperity and Patron licenses while the repository reports no recognised license, so read what those terms allow before putting it in anything commercial. And if you consume the npm package instead of cloning, note that the entry points declared in package.json are webpack output, while the publish script runs only the WESL packager, so what lands on the registry and what you import come out of two different build systems.
Frequently asked questions
What is Lygia and how do I use one function from it?
You include the file you need. The example shader in the README pulls in lygia/space/ratio.glsl, lygia/math/decimate.glsl and lygia/draw/circle.glsl, then calls ratio(st, u_resolution) on the normalized fragment coordinate before drawing.
How do I install Lygia?
Four local routes and one server route. Clone with git, add it as a submodule, use npx degit to clone without git history and reduce the project size by 9MB or more, or take the npm bundle. The server route is a script tag for https://lygia.xyz/resolve.js or resolve.esm.js, which resolve includes online.
Can I shrink Lygia down to one shading language?
Yes, with the prune.py script. The documented invocation is `python prune.py --all --keep glsl`, where the value after --keep names the language to keep and everything else is removed.
What license does Lygia use?
package.json declares "Prosperity License & Patron License" with a link to lygia.xyz/license. The repository's own license metadata reports NOASSERTION, and the tree carries a LICENSE.md at the root, so the three sources do not name the same thing.
Which shading languages does Lygia cover?
The summary sentence names GLSL, HLSL, Metal, WEGL and CUDA. The tree uses the WESL spelling instead of WEGL, with README_WESL.md, wesl.toml, version.wesl and a build:wesl script. There are language specific READMEs for GLSL, Metal, WESL and WebGPU but none for HLSL.
Does Lygia test on anything other than Node?
The scripts include deno run -A --unstable-webgpu npm:vitest run and deno run -A --unstable-webgpu npm:wgsl-test run, plus a native wgsl-test run. The CI entry point ci:check is pnpm test:once && pnpm test:built, which does not include the Deno paths.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/patriciogonzalezvivo-lygia)Star history chart for your README
[](https://hysenlabs.com/projects/patriciogonzalezvivo-lygia)Was this useful?