Library · WebGPU + WGSL

vgpu

A small typed layer over WebGPU that also runs headless.

The reference scene

Not running on this page. vgpu is not a dependency of this site, and rendering a screenshot while implying it was live would be exactly the kind of thing this site exists not to do. The code below is real and is what you would write — the WebGL and WebGPU pages have the same scene actually running, for comparison.

What it is

vgpu is a minimal WebGPU library from Vercel Labs. Its distinguishing idea is that WGSL files behave like TypeScript modules — you import a shader, the loader resolves its import graph at build time, and reflection keeps the bindings correct. A complete full-screen effect comes to about 25 KB gzipped.

The part that is genuinely unusual is the runtime story: the same code runs in the browser, in headless Node against a Dawn-backed adapter, and in a deterministic software mock. That means shaders can be compile-checked and snapshot-rendered in CI rather than eyeballed — which is the reason it is worth a look even if you do not adopt it.

It sits at the opposite end of the scale from the labs on this site. vgpu deliberately removes the pipeline ceremony that the Coordinate Spaces and Projection labs exist to show you, so it is a good tool to reach for once you already know what it is folding away.

Reach for it when

  • You are writing WGSL seriously and want shaders to be modules with real imports rather than template strings.
  • You want shader validation and rendered output checked in CI, not by looking at it.
  • You want WebGPU without hand-writing pipeline and bind-group descriptors every time.

Look elsewhere when

  • You need WebGL support. vgpu is WebGPU only — there is no fallback path.
  • You are learning the pipeline. It hides precisely the plumbing you are trying to see.
  • You want a scene graph with loaders and controls. That is a different tool.

The code

The same plasma, written the way vgpu wants it written.

InstallShell2 lines
npm install vgpu
npm install -D @webgpu/types
A full-screen effectTypeScript12 lines
import { clock, effect, frameLoop, init, surface } from 'vgpu';
import plasma from './plasma.wgsl';

const gpu = await init();
const view = surface(gpu, canvas, { dpr: [1, 2] });
const plasmaEffect = effect(gpu, plasma);
const time = clock(gpu);

frameLoop(gpu, (frame) => {
  plasmaEffect.set({ time: time.time });
  frame.pass(view, plasmaEffect);
});

Follows the shape of vgpu’s own getting-started guide. Compare it with the WebGPU page: same output, no pipeline or bind-group descriptors in sight.

The bit that is actually novel — rendering in a testTypeScript10 lines
import { draw, frame, init, target } from 'vgpu/node';
import triangle from './triangle.wgsl';

const gpu = await init();
const colour = target(gpu, { size: [256, 256], format: 'rgba8unorm' });

frame(gpu, (f) => f.pass(colour, draw(gpu, { shader: triangle })));

const pixels = await colour.read();
gpu.dispose();

Headless Node, real pixels back. This is what makes shader output assertable in CI.

Wiring the WGSL loader into Next.jsTypeScript10 lines
// next.config.ts
const nextConfig = {
  turbopack: {
    rules: {
      '*.wgsl': { loaders: ['@vgpu/wgsl/loader-webpack'], as: '*.js' },
    },
  },
};

export default nextConfig;

Needed only if you want .wgsl files rather than strings. effect() accepts a plain string too.

Things that will catch you

A .wgsl import is an object, not a string
The default export is a ShaderSource ({ version, wgsl }). Hand it straight to effect(), which accepts either — do not reach into .wgsl yourself.
TypeScript needs to be told what .wgsl is
Without an ambient declaration, importing a shader fails to compile. Referencing @vgpu/wgsl/wgsl-types from a .d.ts is the one-line fix.
It inherits every WebGPU constraint
No WebGPU, no vgpu. The abstraction is over the ceremony, not over the availability.

Where to learn it

These and 35 more on the reading path.