Simple way to run WebGPU shaders on HTML Canvas.
To install, run:
npm i --save-exact @wgsl-canvas/core
If you're using TypeScript, it would be helpful to add @webgpu/types, so your codebase will be aware of WebGPU-related types.
To install them, run:
npm i --save-dev @webgpu/types
Then add them into your tsconfig.json
:
{
// ...
"compilerOptions": {
// ...
"types": ["@webgpu/types"]
}
}
Here's the base example for you to get started:
import { WGSLCanvas } from "@wgsl-canvas/core";
// 1. Check WebGPU support
if (!WGSLCanvas.isSupported()) {
alert("WebGPU is not supported in this browser");
return;
}
// 2. Create a canvas
const canvas = document.createElement("canvas");
canvas.width = 500;
canvas.height = 500;
document.body.appendChild(canvas);
// 3. Create an instance of "WGSLCanvas" and initialize it
const wgslCanvas = new WGSLCanvas({ canvas });
await wgslCanvas.init();
// 4. Make your first render
wgslCanvas.render();
If everything is set up correctly, you should see this picture (which is the default fragment shader located under WGSLCanvas.SHADER_FRAGMENT_DEFAULT
static field):
To pass your custom shader, define it as a string of WGSL code.
const shaderFragment = /* wgsl */`
struct FragmentOutput {
@location(0) color: vec4<f32>,
}
@fragment
fn fragment_main() -> FragmentOutput {
var output: FragmentOutput;
output.color = vec4<f32>(0.1, 0.2, 0.25, 1.0);
return output;
}
`;
And then pass it to WGSLCanvas
instance via shaderFragment
property:
wgslCanvas.shaderFragment = shaderFragment;
Tip
If you want to store your WGSL code under .wgsl
files, you should configure your bundler to be able to resolve them as strings. The easiest way is to start with Vite, which can do this out of the box via ?raw
suffix.
See full example here:
To pass uniforms to your shader, you should first define them in uniformsKeys
array in your WGSLCanvas
instance:
wgslCanvas.uniformsKeys = ["time", "color1", "color2"];
Then, you can pass the values in uniforms
object:
wgslCanvas.uniforms.time = 0.0;
wgslCanvas.uniforms.color1 = [1.0, 0.0, 0.0];
wgslCanvas.uniforms.color2 = [0.0, 0.0, 1.0];
Then, they'll be available under var<uniform>
object at @group(0)
, @binding(0)
in your WGSL shader:
@group(0) @binding(0) var<uniform> uniforms: Uniforms;
struct Uniforms {
time: f32,
color1: vec3<f32>,
color2: vec3<f32>,
}
Important
The order of keys in struct Uniforms
must be the same as defined in uniformsKeys
array!
See full example here:
Make sure you have your texture file served under some URL (can be absolute or relative).
Then, you can load it via WGSLCanvas.loadTexture
static method to get an ImageBitmap
image:
const textureUrl = "https://example.com/YOUR_TEXTURE.jpg";
const texture = await WGSLCanvas.loadTexture(textureUrl);
Then, pass it into textures
array of your WgslCanvas
instance:
wgslCanvas.textures = [texture];
In WGSL shader, it'll appear under the following vars:
@group(0) @binding(0) var texture_sampler: sampler;
@group(0) @binding(1) var texture: texture_2d<f32>;
Note
If you have uniforms, they'll appear at @binding(0)
, but sampler
and textures
will appear under their bindings incremented by 1.
See full example here:
See various examples at apps/examples/src/examples.
To run them live, you can clone this repository, install dependencies via npm install
and then run
npm run dev
which will open the dev server at http://localhost:5173 by Vite.
Check out auto-generated docs here: tsdocs.dev:@wgsl-canvas/core
See CHANGELOG.md