Open-source project
gl-transitions/gl-transitions avatar
gl-transitions/gl-transitions

GL Transitions: a shader contract for morphing one texture into another

The open collection of GL Transitions

2,143 stars324 forksGLSLNOASSERTION

At a glance

What is it?
gl-transitions collects WebGL shaders that blend two textures over a single progress value, and its README doubles as a small specification for writing your own.
Who is it for?
gl-transitions earns its place when your transitions need to be resolution independent, because ratio and uv are handed to the shader instead of being hardcoded into a canvas size. It is a specification plus a library of shaders, not an animation runtime: something has to drive progress from 0.0 to 1.0 and render the result, and the repository does not do that part.
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 106 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 September 28, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A transition is a function, not a video clip

The whole idea fits in a sentence from the specification: a transition is an animation that smoothly animates the intermediary steps between 2 textures, `from` and `to`, with the step given by a `progress` value moving from `0.0` to `1.0`. That framing matters, because it rules out the usual approach of shipping pre-rendered clips or a fixed list of keyframes. Nothing is baked. The shader is evaluated per pixel for every value of progress, and the intermediate frames are whatever the maths produces.

The specification also states one hard constraint that any conforming transition has to respect. When progress is 0.0, only the `from` texture may be rendered, and when progress is 1.0, only the `to` texture. The README marks this as an important feature to respect, because a transition that has faded halfway at its own endpoints cannot be used to build a slideshow where one image must be fully visible at the boundary. Every shader in the collection is written against that boundary condition.

The repository is small and its layout matches that narrow purpose. The tree holds `transitions/`, a `scripts/` directory, a `LICENSE` file, and `CONTRIBUTING.md`. There is no build system, no runtime library and no test harness in the tree; the shaders are the product. The last push landed on 2026-06-22, and the README notes that every commit reaching the master branch automatically produces a new npm minor release, which is the closest thing the project has to a release cadence.

The transition(vec2 uv) signature that every shader implements

A GL Transition is defined as GLSL code implementing a `transition` function that takes a `vec2 uv` pixel position and returns a `vec4` color. The specification version is v1, tied to the npm package major, and the README is explicit that breaking changes will bump that major and respect semver.

The smallest conforming transition in the document is a crossfade, which is also the best way to read the contract:

glsl
// transition of a simple fade.
vec4 transition (vec2 uv) {
  return mix(
    getFromColor(uv),
    getToColor(uv),
    progress
  );
}

Six lines, and every one of them is load bearing. `progress` is a contextual variable, so it is not declared in the shader, and `mix` interpolates between the two sampled colors as progress advances. Nothing about the transition's duration, easing or trigger lives in the shader. The host application owns those, which is why the same shader can be reused across a slide deck, a drag gesture and a loading screen.

Because the shader is evaluated per pixel, cost scales with the number of pixels the host renders. A transition that samples the from and to textures three times each is roughly twice the work of the fade at the same resolution, on hardware where texture reads are the dominant cost. The collection policy acknowledges this indirectly, since it says a less generic transition may be kept because it might be more performant for some users.

Why the spec forbids touching the textures directly

The specification is unusually firm about one thing: do not call `texture2D` to read from the `from` and `to` textures directly, use `getFromColor(vec2)` and `getToColor(vec2)` instead. The reason given is not style. Wrapping the lookup means the implementer can add ratio preserving support and decide what color to return for coordinates that fall outside the texture.

That is the entire reason `ratio` exists as a contextual variable. It is the viewport aspect ratio, `width / height`, and the specification explains that width and height are deliberately not exposed because a transition should be scalable to any size. `ratio` is there for the cases where shape has to be preserved, such as drawing squares rather than letting them stretch. A shader written against raw texture access would have to assume a pixel size or duplicate texture geometry to do the same thing.

In practice the split of responsibilities reads like this. The shader decides what the blend looks like. The host decides the render target, the aspect ratio, the range of progress and how coordinates outside the source textures are handled. For a reader who wants to know what a library like `gl-transition-libs` is for, this is the answer: the collection is the shader side, and those libraries are the plumbing that drives it.

Parameters are declared by commenting out their defaults

Transition parameters are the values a user can tweak, and the specification constrains them to stay constant across a full run. That is a real restriction on shader authors: no easing curves expressed as a parameter that changes with progress, no time-varying effects.

The interesting part is the syntax. The README says it is unfortunately not possible to initialize a uniform in GLSL 120 (WebGL 1), so the project uses commented code as the default value declaration:

glsl
uniform float foo; // = 42.0
uniform vec2 foo; // = vec2(42.0, 42.0)

Three more variants are supported, including a block comment after the semicolon and several uniforms sharing one line:

glsl
uniform float foo/* = 42.0 */;
uniform vec2 foo /*= vec2(42.0, 42.0)*/, bar /* = vec2(1.) */;
uniform vec2 foo, bar; // = vec2(1.0, 2.0); // both at the same time ! (needs a ';' if you have this second //, like usual glsl code)

The last line carries a real gotcha, since a second line comment needs the semicolon to terminate the declaration. The underlying rule is simple enough that the collection states it as a heuristic: any constant you define in your transitions is a potential parameter to expose. That makes parameter exposure an authoring discipline rather than a feature you switch on.

A collection that keeps its near-duplicates on purpose

The collection policy is the most unusual paragraph in the repository and it explains a lot about how the project is searched. If two transitions are duplicated, or one is more generic than another, the answer is not necessarily to drop the less generic one. The stated reasons are that it might be more performant, that it might fit for some users, and that they want to keep backward compatibility.

If a transition does eventually get dropped, the process is spelled out: deprecate it first, then remove it at the next major bump. That is a conservative stance for a collection whose entire value is searchability, and it has an obvious cost. A folder full of several dozen similar dissolves and wipes becomes harder to scan, and the maintainers have chosen breadth over tidiness. Contributors thinking about whether their shader belongs there should read that policy before writing, because the bar for inclusion is lower than the duplication rate suggests.

The distribution story is deliberately thin. There are no GitHub releases in the repository, and instead the README states that each merge to master triggers an npm minor release of the `gl-transitions` package. Browsing happens on the homepage at gl-transitions.com, with gl-transitions.surge.sh listed as alternative hosting, and the companion libraries live in the separate `gl-transition-libs` repository. The README also notes that the document itself is the technical version, with the homepage carrying the informal explanation.

What the specification leaves for the implementer

It is worth being blunt about the boundary. GL Transitions defines what a transition looks like and nothing about when it runs. Progress generation, easing, duration, playback controls, rendering into a canvas and out of bounds color handling all belong to whatever loads the shader. That is a clean division and it is why the same collection works in a browser page, in a video pipeline and in a design tool.

It also means the repository cannot tell you whether a given shader is fast on your hardware, and the collection policy's mention of performance is qualitative rather than measured. Nothing in the README or the tree suggests a benchmark suite, so shader cost has to be judged by reading the source: count the texture reads, and remember that the host renders one invocation per pixel.

Licensing is the other gap worth naming. A `LICENSE` file sits at the root of the tree, but the README does not state the terms, so anyone planning to ship these shaders inside a product should read that file directly rather than assume the permissive licenses common to similar shader collections. The topics on the repository, glsl, transition, transitions and webgl, describe a small and honest scope: shader source, a written contract, and a browser where you can see the results.

Editorial conclusion

gl-transitions earns its place when your transitions need to be resolution independent, because ratio and uv are handed to the shader instead of being hardcoded into a canvas size. It is a specification plus a library of shaders, not an animation runtime: something has to drive progress from 0.0 to 1.0 and render the result, and the repository does not do that part. The collection deliberately keeps near-duplicate transitions instead of pruning them, so searching it is a real cost and the homepage at gl-transitions.com is the place to browse. Start by copying the fade shader out of the specification and running it in the page, then read the two sections on contextual functions and transition parameters before writing anything of your own.

Frequently asked questions

What does a transition look like in gl-transitions?

It is a GLSL function named transition that takes a vec2 uv coordinate and returns a vec4 color, mixing the from and to textures according to the contextual progress value. The specification also requires that the from texture is the only one rendered at progress 0.0, and the to texture the only one at progress 1.0.

How do I expose a parameter in a gl-transitions shader?

Declare the uniform and write its default value in a comment, because WebGL 1 cannot initialize a uniform. The specification accepts a trailing line comment, a block comment, and several uniforms on one line, as long as a second line comment is preceded by a semicolon.

Is the gl-transitions collection available as an npm package?

Yes. The README points at the gl-transitions package on npm and states that every commit merged into the master branch automatically publishes a new minor release. The repository itself carries no GitHub releases, and there is no documentation directory in the tree.

Official sources

  1. gl-transitions/gl-transitions on GitHub
  2. Issues
  3. Project website
  4. README
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.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/gl-transitions-gl-transitions.svg)](https://hysenlabs.com/projects/gl-transitions-gl-transitions)