Complete TypeScript type definitions for the WebGPU standard enabling type-safe GPU programming.
—
Render pipelines, compute pipelines, and shader modules for defining GPU programs and rendering state.
Compiled shader code that can be used in pipelines.
interface GPUShaderModule {
/** Optional debug label */
readonly label: string | undefined;
/**
* Gets compilation information including errors and warnings
* @returns Promise resolving to compilation info
*/
getCompilationInfo(): Promise<GPUCompilationInfo>;
}
interface GPUShaderModuleDescriptor extends GPUObjectDescriptorBase {
/** WGSL shader code */
code: string;
/** Optional compilation hints */
hints?: Record<string, GPUShaderModuleCompilationHint>;
}
interface GPUShaderModuleCompilationHint {
/** Entry point name */
entryPoint?: string;
/** Pipeline layout for optimization */
layout?: GPUPipelineLayout | "auto";
}
interface GPUCompilationInfo {
/** Array of compilation messages */
readonly messages: ReadonlyArray<GPUCompilationMessage>;
}
interface GPUCompilationMessage {
/** Message text */
readonly message: string;
/** Message type */
readonly type: GPUCompilationMessageType;
/** Line number (1-based) */
readonly lineNum: number;
/** Line position (1-based) */
readonly linePos: number;
/** Byte offset in source */
readonly offset: number;
/** Length of the relevant source region */
readonly length: number;
}
type GPUCompilationMessageType = "error" | "warning" | "info";Defines the resource binding layout for a pipeline.
interface GPUPipelineLayout {
/** Optional debug label */
readonly label: string | undefined;
}
interface GPUPipelineLayoutDescriptor extends GPUObjectDescriptorBase {
/** Array of bind group layouts */
bindGroupLayouts: Iterable<GPUBindGroupLayout>;
}Graphics pipeline for vertex processing and fragment shading.
interface GPURenderPipeline {
/** Optional debug label */
readonly label: string | undefined;
/**
* Gets bind group layout at the specified index
* @param index - Bind group index
* @returns The bind group layout
*/
getBindGroupLayout(index: number): GPUBindGroupLayout;
}
interface GPURenderPipelineDescriptor extends GPUPipelineDescriptorBase {
/** Vertex stage configuration */
vertex: GPUVertexState;
/** Primitive assembly configuration */
primitive?: GPUPrimitiveState;
/** Depth/stencil state */
depthStencil?: GPUDepthStencilState;
/** Multisample state */
multisample?: GPUMultisampleState;
/** Fragment stage configuration */
fragment?: GPUFragmentState;
}
interface GPUPipelineDescriptorBase extends GPUObjectDescriptorBase {
/** Pipeline layout */
layout: GPUPipelineLayout | "auto";
}
interface GPUVertexState extends GPUProgrammableStage {
/** Vertex buffer layouts */
buffers?: Iterable<GPUVertexBufferLayout | null>;
}
interface GPUProgrammableStage {
/** Shader module */
module: GPUShaderModule;
/** Entry point function name */
entryPoint?: string;
/** Pipeline constants */
constants?: Record<string, GPUPipelineConstantValue>;
}
interface GPUVertexBufferLayout {
/** Stride between vertices in bytes */
arrayStride: GPUSize64;
/** Step mode for vertex fetching */
stepMode?: GPUVertexStepMode;
/** Vertex attributes */
attributes: Iterable<GPUVertexAttribute>;
}
interface GPUVertexAttribute {
/** Vertex format */
format: GPUVertexFormat;
/** Byte offset within vertex */
offset: GPUSize64;
/** Shader location binding */
shaderLocation: GPUIndex32;
}
interface GPUPrimitiveState {
/** Primitive topology */
topology?: GPUPrimitiveTopology;
/** Strip index format */
stripIndexFormat?: GPUIndexFormat;
/** Front face winding */
frontFace?: GPUFrontFace;
/** Face culling mode */
cullMode?: GPUCullMode;
/** Whether to enable conservative rasterization */
unclippedDepth?: boolean;
}
interface GPUMultisampleState {
/** Number of samples */
count?: GPUSize32;
/** Sample mask */
mask?: GPUSampleMask;
/** Alpha to coverage */
alphaToCoverageEnabled?: boolean;
}
interface GPUFragmentState extends GPUProgrammableStage {
/** Color target states */
targets: Iterable<GPUColorTargetState | null>;
}
interface GPUColorTargetState {
/** Color format */
format: GPUTextureFormat;
/** Blend state */
blend?: GPUBlendState;
/** Write mask */
writeMask?: GPUColorWriteFlags;
}
interface GPUBlendState {
/** Color blend component */
color: GPUBlendComponent;
/** Alpha blend component */
alpha: GPUBlendComponent;
}
interface GPUBlendComponent {
/** Blend operation */
operation?: GPUBlendOperation;
/** Source factor */
srcFactor?: GPUBlendFactor;
/** Destination factor */
dstFactor?: GPUBlendFactor;
}
interface GPUDepthStencilState {
/** Depth/stencil format */
format: GPUTextureFormat;
/** Whether depth writes are enabled */
depthWriteEnabled?: boolean;
/** Depth comparison function */
depthCompare?: GPUCompareFunction;
/** Stencil front face state */
stencilFront?: GPUStencilFaceState;
/** Stencil back face state */
stencilBack?: GPUStencilFaceState;
/** Stencil read mask */
stencilReadMask?: GPUStencilValue;
/** Stencil write mask */
stencilWriteMask?: GPUStencilValue;
/** Depth bias constant */
depthBias?: GPUDepthBias;
/** Depth bias slope scale */
depthBiasSlopeScale?: number;
/** Depth bias clamp */
depthBiasClamp?: number;
}
interface GPUStencilFaceState {
/** Comparison function */
compare?: GPUCompareFunction;
/** Fail operation */
failOp?: GPUStencilOperation;
/** Depth fail operation */
depthFailOp?: GPUStencilOperation;
/** Pass operation */
passOp?: GPUStencilOperation;
}
type GPUStencilOperation =
| "keep" | "zero" | "replace" | "invert"
| "increment-clamp" | "decrement-clamp"
| "increment-wrap" | "decrement-wrap";Compute shader pipeline for general-purpose GPU computing.
interface GPUComputePipeline {
/** Optional debug label */
readonly label: string | undefined;
/**
* Gets bind group layout at the specified index
* @param index - Bind group index
* @returns The bind group layout
*/
getBindGroupLayout(index: number): GPUBindGroupLayout;
}
interface GPUComputePipelineDescriptor extends GPUPipelineDescriptorBase {
/** Compute stage configuration */
compute: GPUProgrammableStage;
}Common functionality shared by all pipeline types.
interface GPUPipelineBase {
/** Optional debug label */
readonly label: string | undefined;
/**
* Gets bind group layout at the specified index
* @param index - Bind group index
* @returns The bind group layout
*/
getBindGroupLayout(index: number): GPUBindGroupLayout;
}// Create a vertex shader
const vertexShader = device.createShaderModule({
code: `
struct VertexInput {
@location(0) position: vec3<f32>,
@location(1) normal: vec3<f32>,
@location(2) uv: vec2<f32>,
}
struct VertexOutput {
@builtin(position) position: vec4<f32>,
@location(0) normal: vec3<f32>,
@location(1) uv: vec2<f32>,
}
@group(0) @binding(0) var<uniform> mvpMatrix: mat4x4<f32>;
@vertex
fn main(input: VertexInput) -> VertexOutput {
var output: VertexOutput;
output.position = mvpMatrix * vec4<f32>(input.position, 1.0);
output.normal = input.normal;
output.uv = input.uv;
return output;
}
`,
label: "Vertex Shader"
});
// Create a fragment shader
const fragmentShader = device.createShaderModule({
code: `
struct FragmentInput {
@location(0) normal: vec3<f32>,
@location(1) uv: vec2<f32>,
}
@group(1) @binding(0) var baseColorTexture: texture_2d<f32>;
@group(1) @binding(1) var baseColorSampler: sampler;
@fragment
fn main(input: FragmentInput) -> @location(0) vec4<f32> {
let baseColor = textureSample(baseColorTexture, baseColorSampler, input.uv);
let lighting = max(dot(normalize(input.normal), vec3<f32>(0.0, 1.0, 0.0)), 0.1);
return vec4<f32>(baseColor.rgb * lighting, baseColor.a);
}
`,
label: "Fragment Shader"
});
// Check compilation info
const vertexInfo = await vertexShader.getCompilationInfo();
for (const message of vertexInfo.messages) {
if (message.type === "error") {
console.error(`Shader error at line ${message.lineNum}: ${message.message}`);
}
}// Create pipeline layout
const pipelineLayout = device.createPipelineLayout({
bindGroupLayouts: [
uniformsBindGroupLayout,
materialBindGroupLayout
],
label: "Render Pipeline Layout"
});
// Create render pipeline
const renderPipeline = device.createRenderPipeline({
layout: pipelineLayout,
vertex: {
module: vertexShader,
entryPoint: "main",
buffers: [
{
arrayStride: 32, // 3 * 4 + 3 * 4 + 2 * 4 = position + normal + uv
attributes: [
{
format: "float32x3",
offset: 0,
shaderLocation: 0 // position
},
{
format: "float32x3",
offset: 12,
shaderLocation: 1 // normal
},
{
format: "float32x2",
offset: 24,
shaderLocation: 2 // uv
}
]
}
]
},
fragment: {
module: fragmentShader,
entryPoint: "main",
targets: [
{
format: "bgra8unorm",
blend: {
color: {
srcFactor: "src-alpha",
dstFactor: "one-minus-src-alpha",
operation: "add"
},
alpha: {
srcFactor: "one",
dstFactor: "one-minus-src-alpha",
operation: "add"
}
}
}
]
},
primitive: {
topology: "triangle-list",
cullMode: "back",
frontFace: "ccw"
},
depthStencil: {
format: "depth24plus-stencil8",
depthWriteEnabled: true,
depthCompare: "less"
},
multisample: {
count: 4,
alphaToCoverageEnabled: false
},
label: "Mesh Render Pipeline"
});// Create compute shader
const computeShader = device.createShaderModule({
code: `
@group(0) @binding(0) var<storage, read> inputData: array<f32>;
@group(0) @binding(1) var<storage, read_write> outputData: array<f32>;
@compute @workgroup_size(64)
fn main(@builtin(global_invocation_id) globalId: vec3<u32>) {
let index = globalId.x;
if (index >= arrayLength(&inputData)) {
return;
}
outputData[index] = inputData[index] * 2.0;
}
`,
label: "Double Values Compute Shader"
});
// Create compute pipeline
const computePipeline = device.createComputePipeline({
layout: "auto",
compute: {
module: computeShader,
entryPoint: "main"
},
label: "Double Values Pipeline"
});
// Get the auto-generated bind group layout
const computeBindGroupLayout = computePipeline.getBindGroupLayout(0);// Shader with constants
const advancedShader = device.createShaderModule({
code: `
override workgroupSize: u32 = 64;
override multiplier: f32 = 1.0;
@group(0) @binding(0) var<storage, read_write> data: array<f32>;
@compute @workgroup_size(workgroupSize, 1, 1)
fn main(@builtin(global_invocation_id) globalId: vec3<u32>) {
let index = globalId.x;
if (index >= arrayLength(&data)) {
return;
}
data[index] = data[index] * multiplier;
}
`,
label: "Parameterized Compute Shader"
});
// Create pipeline with constants
const parameterizedPipeline = device.createComputePipeline({
layout: "auto",
compute: {
module: advancedShader,
entryPoint: "main",
constants: {
workgroupSize: 128,
multiplier: 2.5
}
},
label: "Parameterized Pipeline"
});const multiTargetPipeline = device.createRenderPipeline({
layout: pipelineLayout,
vertex: {
module: vertexShader,
entryPoint: "main",
buffers: [vertexBufferLayout]
},
fragment: {
module: multiTargetFragmentShader,
entryPoint: "main",
targets: [
{ format: "rgba8unorm" }, // Color target 0
{ format: "rgba16float" }, // Color target 1 (HDR)
{ format: "rg16float" }, // Color target 2 (normals)
null, // Skip target 3
{ format: "r8uint" } // Color target 4 (object ID)
]
},
primitive: {
topology: "triangle-list"
},
label: "G-Buffer Pipeline"
});// Create pipelines asynchronously for better performance
const [renderPipelineAsync, computePipelineAsync] = await Promise.all([
device.createRenderPipelineAsync({
layout: renderPipelineLayout,
vertex: { module: vertexShader, entryPoint: "main" },
fragment: {
module: fragmentShader,
entryPoint: "main",
targets: [{ format: "bgra8unorm" }]
},
label: "Async Render Pipeline"
}),
device.createComputePipelineAsync({
layout: "auto",
compute: { module: computeShader, entryPoint: "main" },
label: "Async Compute Pipeline"
})
]);
console.log("Both pipelines created asynchronously");// Create shader with potential compilation issues
const shaderWithError = device.createShaderModule({
code: `
@vertex
fn main() -> @builtin(position) vec4<f32> {
// Missing required vertex output
return vec4<f32>(0.0, 0.0, 0.0, 1.0);
}
`,
label: "Test Shader"
});
// Check for compilation errors
const compilationInfo = await shaderWithError.getCompilationInfo();
if (compilationInfo.messages.length > 0) {
console.log("Compilation messages:");
for (const message of compilationInfo.messages) {
const level = message.type.toUpperCase();
console.log(`${level} at line ${message.lineNum}:${message.linePos} - ${message.message}`);
}
}
// Handle pipeline creation errors
device.pushErrorScope("validation");
const pipeline = device.createRenderPipeline({
layout: "auto",
vertex: { module: shaderWithError, entryPoint: "main" },
fragment: {
module: fragmentShader,
entryPoint: "main",
targets: [{ format: "bgra8unorm" }]
}
});
const error = await device.popErrorScope();
if (error) {
console.error("Pipeline creation failed:", error.message);
}// Create multiple specialized pipelines from the same shader
const basePipelineDesc: GPURenderPipelineDescriptor = {
layout: pipelineLayout,
vertex: {
module: vertexShader,
entryPoint: "main",
buffers: [vertexBufferLayout]
},
fragment: {
module: fragmentShader,
entryPoint: "main",
targets: [{ format: "bgra8unorm" }]
}
};
// Opaque rendering pipeline
const opaquePipeline = device.createRenderPipeline({
...basePipelineDesc,
primitive: {
topology: "triangle-list",
cullMode: "back"
},
depthStencil: {
format: "depth24plus",
depthWriteEnabled: true,
depthCompare: "less"
},
label: "Opaque Pipeline"
});
// Transparent rendering pipeline
const transparentPipeline = device.createRenderPipeline({
...basePipelineDesc,
primitive: {
topology: "triangle-list",
cullMode: "none"
},
fragment: {
...basePipelineDesc.fragment!,
targets: [{
format: "bgra8unorm",
blend: {
color: {
srcFactor: "src-alpha",
dstFactor: "one-minus-src-alpha"
},
alpha: {
srcFactor: "one",
dstFactor: "one-minus-src-alpha"
}
}
}]
},
depthStencil: {
format: "depth24plus",
depthWriteEnabled: false,
depthCompare: "less-equal"
},
label: "Transparent Pipeline"
});Install with Tessl CLI
npx tessl i tessl/npm-webgpu--types