WebGL shader effects applied to HTML image elements positioned with CSS, showing displacement and parallax animations synchronized with DOM layout.
Martin Laxenaire built curtains.js to solve a problem most WebGL libraries pretend doesn't exist: nobody wants to do coordinate math to position a shader plane where their hero image lives in the DOM. curtains.js just handles it. You write CSS like normal. The library converts your HTML elements (images, videos, canvases) into WebGL textured planes that sit exactly where you told them to, responding to scroll and resize like they never left the document flow. It's deeply practical and a little bit magic. The examples range from straightforward parallax effects to flowmap displacement shaders that ping-pong between framebuffers, all anchored to divs that could just as easily hold a JPEG.
The technical approach is clean. Under the hood, curtains.js manages texture matrices to handle image cover behavior, coordinates vertex and fragment shaders through a sensible class structure (Curtains, Plane, Texture, RenderTarget), and gives you hooks like onRender() to update uniforms each frame. It's vanilla JavaScript with no framework opinions, though Martin's also published React and Vue wrappers if you need them. The library stays lightweight because it trusts you to write your own shaders instead of trying to abstract GLSL into some awkward API. If you know what a uniform is, you'll be productive in ten minutes.
Check the examples page for commented source code on everything from basic displacement to multi-pass post-processing. The GitHub repo has good docs and an MIT license. Martin's also working on gpu-curtains, a WebGPU successor worth watching. If CSS-driven shader planes sound useful, this is the library.
- Live Demo: https://www.curtainsjs.com
- Source Code: https://github.com/martinlaxenaire/curtainsjs
- Author: Martin Laxenaire (X, LinkedIn, GitHub)