DOM-anchored
Every scene knows its element. u_origin and u_resolution update each frame automatically, no event wiring needed.
Anchor independent WebGL programs to any DOM element. A single
fixed canvas, scissor-tested viewports, one shared render loop.
ScrollRenderer is a WebGL scene manager for inline
effects that scale.
Each ScrollScene tracks a DOM element via getBoundingClientRect(). WebGL's scissor test clips each render to that element's exact pixel bounds.
Scenes outside the viewport are culled automatically by IntersectionObserver, so performance issues end up being minimal.
Every scene knows its element. u_origin and u_resolution update each frame automatically, no event wiring needed.
The rings above centre on this card's exact position in the canvas using u_origin.xy and gl_FragCoord.
A single requestAnimationFrame drives every scene. Zero per-canvas overhead, no scheduling jank.
The traditional answer to multiple WebGL programs on one page is one <canvas> per effect, a separate GPU context for each. Browsers cap active WebGL contexts. Each one competes for GPU memory, initialises its own GL state, and drives its own render loop with zero coordination.
On top of CPU, GPU, and memory load, browsers drop contexts to reclaim resources which means effects disappear without warning. You end up building fragile context managers around the symptom.
ScrollRenderer solves all of this with a single shared context and one coordinated render loop with a coordinator that provides all the required functionality.
Mix real imagery with GL effects on the same shared canvas. ScrollScene and ScrollImage provide simple-to-use, useful hooks to help bring your designs to life.
The HTML document lays the page out, including the placeholders that anchor WebGL programs, which composite into one shared full-screen canvas coordinated by a single renderer.
Extend with onBeforeRender and onAfterRender hooks, or opt out of per-scene clearing and viewport locking independently. Uniforms update automatically.
const renderer = new ScrollRenderer() const scene = new ScrollScene({ element, scene: drawable }) renderer.addScene(scene) // Uniforms updated automatically every frame: // u_time float - elapsed time // u_resolution vec2 - element size in physical px // u_origin vec4 - .xy gl_FragCoord origin // .zw element centre in NDC
The TransformFeedback class handles ping-pong buffers automatically. Complex particle systems run in the shared context alongside fragment-shader scenes with no extra overhead.
clearOnRender: falseu_origin.zw when useViewport is falseScrollRenderer is part of wtc-gl: a lightweight WebGL library by We The Collective.