The canvas
What draws the media: WebGPU where the browser has it, WebGL 2 where not. And what the two were measured at.
import { canvas } from 'gpuslider/canvas';
import { stretch } from 'gpuslider/effects';
canvas( { effects: [ stretch() ], eager: false, density: 2, maxSize: 2048, perspective: 1200 } )
canvas() draws with WebGPU where the browser has it and with WebGL 2 where not. It is 0.3 KB, and loads the layer it takes when the page has time: no page loads the layer it does not draw with. Both layers draw the same picture from the same effects; the tests hold them against each other, effect by effect. canvas:ready says which one it is, and the layer is slider.plugins.gpu or slider.plugins.gl.
canvas( { layer: 'gl' } ) and layer: 'gpu' say which. Who wants the layer in the bundle, and no request for it later, names it:
import { gpu, stretch } from 'gpuslider/gpu'; // WebGPU, or the page draws
import { gl, stretch } from 'gpuslider/gl'; // WebGL 2, or the page draws
The canvas is made at the first sign of use: a pointer over the slider, a touch, the focus, a move. Until then the page draws the slides, which look the same, and the page has loaded without a context and without a shader. A slider that moves by itself (autoplay, a ticker), or whose effects show at rest, gets its canvas when the page has time. eager: true makes it with the slider.
Shaders are compiled on another thread where the browser can, and no frame is drawn while nothing moves.
WebGPU and WebGL, measured
npm run bench makes the same sliders with each layer, in the same browser with the same GPU, and measures. On a Mac with an Apple M5, 2 device pixels per pixel, 2026-09-29, in Chromium 153 (Metal) and WebKit 26.6, both without a window, sliders with stretch and waves. The first two lines are the middle of five runs, the others are one run each:
| WebGL 2 | WebGPU | |
|---|---|---|
| The first slider of a page: drawn after | 82 ms in Chromium, 84 ms in WebKit | 64 ms, 80 ms |
| A slider after it | 50 ms, 51 ms | 33 ms, 33 ms |
| Four more, made together | 169 ms, 100 ms | 33 ms, 33 ms |
| Sliders of one page that the canvas draws | 12 | all: 20 of 20 |
| Script in a frame while 6 sliders move | 0.15 ms, 0.17 ms | 0.33 ms, 0.27 ms |
| Frames that came late while 20 sliders moved for 4 s | 0 of 241 | 0 of 241 |
| Work of the page and of the GPU process, 6 sliders (Chromium) | 10 % and 18 % of a core | 11 % and 18 % |
| The layer in the bundle | 7.0 KB | 9.0 KB |
| Browsers | all | Chrome, Edge, Safari from 26, Firefox on some systems: about 87 % of visitors |
What it says: WebGPU has one device for all sliders of a page, and a shader is made once for all of them. So the second slider is there in two frames, a page has as many sliders on the canvas as it likes, and nothing is taken away from one slider to give it to another. While the sliders move there is no difference to see: both draw every frame. WebGPU needs about twice the script for a frame, which for six sliders is 0.3 ms of the 16.7 that a frame has.
What it does not say: what the GPU does with a frame, which no page can measure; and how it is on a phone. npm run bench -- --headed measures with windows, --write writes the numbers for the site, bench/ in a browser of your own shows the same numbers for that browser.


