API Reference

Complete documentation of all ralph-gpu methods and properties.

modulegpu

The main entry point for initializing WebGPU.

TypeScript
import { gpu, WebGPUNotSupportedError, DeviceCreationError, ShaderCompileError } from "ralph-gpu";
 
// Check if WebGPU is supported in this browser
gpu.isSupported()  // → boolean
 
// Initialize the GPU context
gpu.init(canvas, options?)  // → Promise<GPUContext>

Init Options

TypeScript
interface InitOptions {
  autoResize?: boolean;  // Auto-resize from CSS size (default: false)
  dpr?: number;          // Device pixel ratio (default: min(devicePixelRatio, 2))
  debug?: boolean;       // Enable debug logging (default: false)
}
 
// Recommended: autoResize handles canvas sizing and DPR automatically
const ctx = await gpu.init(canvas, {
  autoResize: true,
});
 
// Manual control:
// If autoResize is false, library uses canvas.width/height directly
// as pixel dimensions. No extra DPR multiplication is applied.
canvas.width = 1280;
canvas.height = 720;
const ctx = await gpu.init(canvas, {
  autoResize: false,
});

classGPUContext

The main context object returned by gpu.init(). Creates and manages all GPU resources.

Factory Methods

TypeScript
// Create a fullscreen pass
ctx.pass(fragmentWGSL, options?)         // → Pass
 
// Create custom geometry material  
ctx.material(wgsl, options?)             // → Material
 
// Create compute shader
ctx.compute(wgsl, options?)              // → ComputeShader
 
// Create render target
ctx.target(width, height, options?)      // → RenderTarget
 
// Create ping-pong buffers
ctx.pingPong(width, height, options?)    // → PingPongTarget
 
// Create multi-render target (MRT)
ctx.mrt(outputs, width, height)          // → MultiRenderTarget
 
// Create storage buffer
ctx.storage(byteSize)                    // → StorageBuffer
 
// Create particle system (instanced quads)
ctx.particles(count, options)            // → Particles
 
// Create custom texture sampler
ctx.createSampler(descriptor?)           // → Sampler

State Management

TypeScript
// Render target management
ctx.setTarget(target)      // Set render target (pass null for screen)
ctx.setTarget(null)        // Render to screen
 
// Viewport and scissor
ctx.setViewport(x?, y?, w?, h?)  // Set viewport rectangle
ctx.setScissor(x?, y?, w?, h?)   // Set scissor rectangle
 
// Clearing
ctx.autoClear = true        // Auto-clear before each draw (default: true)
ctx.clearColor = [r, g, b, a] // Set clear color (default: [0, 0, 0, 1])
ctx.clear(target?, color?)  // Manual clear (color as [r, g, b, a])
 
// Resize
ctx.resize(width, height)   // Resize context and internal buffers

Properties

TypeScript
ctx.width: number         // Canvas width in pixels
ctx.height: number        // Canvas height in pixels
ctx.dpr: number           // Device pixel ratio (get/set)
ctx.time: number          // Elapsed time in seconds
ctx.timeScale: number     // Time multiplier (default: 1)
ctx.paused: boolean       // Pause time updates
ctx.autoClear: boolean    // Auto-clear before draw (default: true)
ctx.clearColor: [number, number, number, number] // Clear color RGBA (default: [0, 0, 0, 1])

Time Control

TypeScript
// Pause/resume time
ctx.paused = true;         // Freeze globals.time
ctx.paused = false;        // Resume time
 
// Time scale
ctx.timeScale = 0.5;       // Slow motion (half speed)
ctx.timeScale = 2.0;       // Fast forward (double speed)
 
// Reset time
ctx.time = 0;              // Jump to time 0

Cleanup

ctx.dispose()

Releases all GPU resources created by this context. Call this when unmounting a component or destroying the canvas.

classPass

A fullscreen shader pass. Renders a fragment shader to the entire render target using an internal quad.

Creation Options

TypeScript
// 1. Simple Mode (Recommended)
// Bindings are auto-generated. Uniforms available via 'uniforms' struct.
const pass = ctx.pass(shaderCode, {
  color: [1, 0.5, 0.2],
  intensity: 0.5,
  uTexture: someTarget,
});
 
// Update values
pass.set("intensity", 0.8);
 
// 2. Manual Mode (explicit bindings)
// Requires manual @group(1) declarations in WGSL.
const pass = ctx.pass(shaderCode, {
  uniforms: {
    color: { value: [1, 0.5, 0.2] },
    intensity: { value: 0.5 },
  },
  blend: "additive",
});
 
// Update values
pass.uniforms.intensity.value = 0.8;

Methods & Properties

TypeScript
// Draw the pass to current target
pass.draw()
 
// Access uniforms
pass.uniforms.amplitude.value = 0.8
 
// Set uniform (alternative syntax)
pass.set("amplitude", 0.8)
 
// Bind a storage buffer
pass.storage("particles", particleBuffer)
 
// Clean up resources
pass.dispose()

classMaterial

A shader with custom vertex code. Use for particles, instanced geometry, or any non-fullscreen rendering.

Creation Options

TypeScript
interface MaterialOptions {
  uniforms?: Record<string, { value: any }>;
  blend?: BlendMode;
  vertexCount?: number;    // Vertices per instance (default: 6)
  instances?: number;      // Number of instances (default: 1)
  topology?: "triangle-list" | "line-list" | "point-list";
}
 
const particles = ctx.material(shaderCode, {
  vertexCount: 6,        // Quad has 6 vertices (2 triangles)
  instances: 10000,      // 10k particles
  blend: "additive",
});

Note: Material has the same methods as Pass (draw(), storage(), dispose(), etc.)

classComputeShader

A compute shader for GPU-parallel computation. Supports storage buffers, texture sampling, and storage texture writes.

TypeScript
// Create compute shader
const sim = ctx.compute(`
  @compute @workgroup_size(64)
  fn main(@builtin(global_invocation_id) id: vec3u) {
    // GPU-parallel computation
  }
`);
 
// Dispatch compute work
sim.dispatch(workgroupsX, workgroupsY?, workgroupsZ?)
 
// Bind storage buffer
sim.storage("data", buffer)
 
// Access uniforms (if any)
sim.uniforms
 
// Cleanup
sim.dispose()
Workgroups: The dispatch count should be totalItems / workgroupSize. If your shader has @workgroup_size(64) and you have 1000 particles, dispatch Math.ceil(1000/64) = 16 workgroups.
New: Compute shaders now support texture sampling and storage texture writes. See Texture Bindings for details.

classRenderTarget

An offscreen texture that can be rendered to and sampled from.

Creation Options

TypeScript
interface TargetOptions {
  format?: "rgba8unorm" | "rgba16float" | "r16float" | "rg16float" | "r32float";
  filter?: "linear" | "nearest";
  wrap?: "clamp" | "repeat" | "mirror";
  usage?: "render" | "storage" | "both";  // NEW: Control texture usage
}
 
const buffer = ctx.target(512, 512, {
  format: "rgba16float",  // HDR
  filter: "linear",       // Smooth sampling
  wrap: "clamp",          // Clamp to edge
});
 
// Storage texture for compute shader writes
const storageTarget = ctx.target(512, 512, {
  format: "rgba16float",
  usage: "storage",       // Enable textureStore() in compute shaders
});

Properties & Methods

TypeScript
target.texture    // TextureReference - stable reference (use in uniforms)
target.gpuTexture // GPUTexture - direct access (becomes invalid after resize)
target.sampler    // GPUSampler
target.view       // GPUTextureView (auto-updated on resize)
target.width      // Width in pixels
target.height     // Height in pixels
target.format     // Texture format string
target.usage      // Usage mode: "render" | "storage" | "both"
 
// Methods
target.resize(width, height)           // Resize (texture refs remain valid!)
target.readPixels(x?, y?, w?, h?)      // → Promise<Uint8Array | Float32Array>
target.dispose()                       // Cleanup resources
 
// Note: Use .texture for uniforms (stable reference)
// Only use .gpuTexture when you need direct GPU texture access

Formats

  • rgba8unorm — Standard 8-bit color
  • rgba16float — HDR, negative values
  • r16float — Single channel float
  • rg16float — Two channel float
  • r32float — High precision single channel

Usage Modes

  • render — Render to & sample (default)
  • storage — Compute shader writes
  • both — All operations

Read Pixels

Returns Uint8Array for 8-bit formats, Float32Array for float formats. This is a GPU→CPU transfer and may be slow.

classPingPongTarget

A pair of render targets for iterative effects. Read from one, write to the other, then swap.

TypeScript
const velocity = ctx.pingPong(128, 128, { format: "rg16float" });
 
// Access buffers
velocity.read    // Current state (RenderTarget)
velocity.write   // Next state (RenderTarget)
 
// Swap after writing
velocity.swap()
 
// Resize both buffers
velocity.resize(width, height)
 
// Cleanup
velocity.dispose()

Usage Pattern

  1. Read from pingPong.read.texture in your shader
  2. Set target to pingPong.write
  3. Draw your pass
  4. Call pingPong.swap()
  5. Repeat next frame

classMultiRenderTarget

Multiple render targets (MRT) for deferred rendering, G-buffers, or any technique requiring simultaneous output to multiple textures.

TypeScript
// Create multiple render targets
const gbuffer = ctx.mrt({
  albedo: { format: "rgba8unorm" },
  normal: { format: "rgba16float" },
  depth: { format: "r32float" },
}, 1024, 1024);
 
// Get individual targets
gbuffer.get("albedo")     // → RenderTarget | undefined
gbuffer.get("normal")     // → RenderTarget | undefined
 
// Or access via property (proxied)
gbuffer.albedo            // → RenderTarget | undefined
 
// Get all views/formats
gbuffer.getViews()        // → GPUTextureView[]
gbuffer.getFormats()      // → string[]
gbuffer.getFirstTarget()  // → RenderTarget | undefined
 
// Dimensions
gbuffer.width             // 1024
gbuffer.height            // 1024
 
// Resize all targets
gbuffer.resize(2048, 2048)
 
// Cleanup
gbuffer.dispose()

Common Use Cases

  • Deferred rendering — Store albedo, normals, depth in separate buffers
  • G-buffer — Multiple material properties for post-processing
  • Multi-output effects — Generate multiple textures in one pass
Access patterns: Use mrt.get("name") for type-safe access, or mrt.name for convenience (proxied property access).

classStorageBuffer

A GPU buffer for large data sets. Used with compute shaders and materials for particles, simulations, etc.

TypeScript
// Create buffer (size in bytes)
const buffer = ctx.storage(4 * 4 * 1000);  // 1000 vec4s
 
// Write data
const data = new Float32Array(4 * 1000);
buffer.write(data)
 
// Access GPUBuffer directly
buffer.gpuBuffer
 
// Cleanup
buffer.dispose()

Size calculation: Multiply the number of items by bytes per item. A vec4f is 16 bytes (4 floats × 4 bytes). For 1000 particles with position and velocity (2 × vec2f), that's 1000 × 16 = 16000 bytes.

classParticles

A helper for instanced quad rendering with full shader control. User provides vertex and fragment shaders — no built-in colors, shapes, or assumptions about data layout.

TypeScript
// Create particle system - instanced quads with full shader control
const particles = ctx.particles(1000, {
  shader: `
    struct Particle { pos: vec2f, size: f32, hue: f32 }
    @group(1) @binding(0) var<storage, read> particles: array<Particle>;
 
    struct VertexOutput {
      @builtin(position) position: vec4f,
      @location(0) uv: vec2f,
      @location(1) hue: f32,
    }
 
    @vertex
    fn vs_main(
      @builtin(instance_index) iid: u32,
      @builtin(vertex_index) vid: u32
    ) -> VertexOutput {
      let p = particles[iid];
      // Built-in helpers: quadOffset(), quadUV()
      let quadPos = quadOffset(vid) * p.size;
      
      var out: VertexOutput;
      out.position = vec4f(p.pos + quadPos, 0.0, 1.0);
      out.uv = quadUV(vid);
      out.hue = p.hue;
      return out;
    }
 
    @fragment
    fn fs_main(in: VertexOutput) -> @location(0) vec4f {
      // Circle SDF
      let d = length(in.uv - 0.5);
      if (d > 0.5) { discard; }
      return vec4f(1.0, in.hue, 0.5, 1.0);
    }
  `,
  bufferSize: 1000 * 16,  // 16 bytes per particle
  blend: "alpha",
});
 
// Write particle data
const data = new Float32Array(1000 * 4);
// Fill data: [x, y, size, hue] per particle
particles.write(data);
 
// Draw all particles
particles.draw();
 
// Access underlying resources
particles.storageBuffer     // → StorageBuffer
particles.underlyingMaterial // → Material

Built-in WGSL Helpers

  • quadOffset(vid: u32) → vec2f — Quad corner position (-0.5 to 0.5)
  • quadUV(vid: u32) → vec2f — UV coordinates (0 to 1)

What You Control

  • Particle struct layout — Any data you need (position, size, color, age, etc.)
  • Vertex shader — Position, size, rotation, billboarding, etc.
  • Fragment shader — Shape via SDF, color, effects (squares, circles, triangles)
Why not point-list? WebGPU's point-list topology renders points as exactly 1 pixel with no size control. The Particles helper uses instanced quads (2 triangles per particle) to support variable sizes.

classSampler

A texture sampler with explicit control over filtering and wrapping modes. Samplers can be reused across multiple textures and shaders for consistency and performance.

TypeScript
// Create custom samplers for explicit texture filtering control
const linearClamp = ctx.createSampler({
  magFilter: "linear",
  minFilter: "linear",
  addressModeU: "clamp-to-edge",
  addressModeV: "clamp-to-edge",
});
 
const nearestRepeat = ctx.createSampler({
  magFilter: "nearest",
  minFilter: "nearest",
  addressModeU: "repeat",
  addressModeV: "repeat",
});
 
// Reuse across multiple textures and shaders
const uniforms = {
  texture1: { value: tex1.texture },
  sampler1: { value: linearClamp },
  texture2: { value: tex2.texture },
  sampler2: { value: nearestRepeat },
};

Sampler Options

TypeScript
interface SamplerDescriptor {
  magFilter?: "linear" | "nearest";           // Default: "linear"
  minFilter?: "linear" | "nearest";           // Default: "linear"
  mipmapFilter?: "linear" | "nearest";        // Default: "linear"
  addressModeU?: "clamp-to-edge" | "repeat" | "mirror-repeat";  // Default: "clamp-to-edge"
  addressModeV?: "clamp-to-edge" | "repeat" | "mirror-repeat";  // Default: "clamp-to-edge"
  addressModeW?: "clamp-to-edge" | "repeat" | "mirror-repeat";  // Default: "clamp-to-edge"
  lodMinClamp?: number;                       // Default: 0
  lodMaxClamp?: number;                       // Default: 32
  compare?: "never" | "less" | "equal" | "less-equal" | "greater" | "not-equal" | "greater-equal" | "always";
  maxAnisotropy?: number;                     // Default: 1
}

Properties & Methods

TypeScript
sampler.gpuSampler    // GPUSampler - use in uniforms
sampler.descriptor    // SamplerDescriptor (readonly)
 
// Cleanup
sampler.dispose()     // No-op currently (kept for API consistency)

Common Patterns

  • Linear Clamp — Blur, postprocessing, smooth sampling at edges
  • Nearest Repeat — Pixel art, tiling textures, retro effects
  • Mirror Repeat — Seamless tiling without visible seams
Performance tip: Create samplers once during initialization and reuse them across multiple textures and shaders instead of recreating them every frame.

Blend Modes

Control how colors are combined when rendering.

Presets & Custom

TypeScript
// Preset blend modes
ctx.pass(shader, { blend: "alpha" })      // Standard transparency
ctx.pass(shader, { blend: "additive" })   // Add colors (glow, fire)
ctx.pass(shader, { blend: "multiply" })   // Multiply (darken)
ctx.pass(shader, { blend: "screen" })     // Screen (lighten)
 
// Custom blend configuration
ctx.pass(shader, {
  blend: {
    color: {
      src: "src-alpha",
      dst: "one",
      operation: "add"
    },
    alpha: {
      src: "one",
      dst: "one-minus-src-alpha",
      operation: "add"
    }
  }
});

Blend Factors & Operations

TypeScript
// Blend factors
"zero"                  // 0
"one"                   // 1
"src"                   // Source color/alpha
"one-minus-src"         // 1 - source
"src-alpha"             // Source alpha
"one-minus-src-alpha"   // 1 - source alpha
"dst"                   // Destination color/alpha
"one-minus-dst"         // 1 - destination
"dst-alpha"             // Destination alpha
"one-minus-dst-alpha"   // 1 - destination alpha
 
// Blend operations
"add"                   // src + dst
"subtract"              // src - dst
"reverse-subtract"      // dst - src
"min"                   // min(src, dst)
"max"                   // max(src, dst)

alpha

Standard transparency

additive

Glow, fire, bright effects

multiply

Darken, shadows

screen

Lighten, highlights

Auto-Injected Globals

Every shader automatically has access to the globals uniform — no declaration needed.

WGSL
struct Globals {
  resolution: vec2f,  // Current render target size in pixels
  time: f32,          // Seconds since init (affected by timeScale)
  deltaTime: f32,     // Seconds since last frame
  frame: u32,         // Frame count since init
  aspect: f32,        // resolution.x / resolution.y
}
 
// Automatically available in all shaders
@group(0) @binding(0) var<uniform> globals: Globals;

resolution

Width and height of current render target in pixels.

time

Seconds since init. Affected by timeScale and paused.

deltaTime

Seconds since last frame. Use for frame-rate independent animation.

frame

Integer frame count. Useful for alternating effects or debugging.

aspect

Resolution width divided by height. Use to correct for non-square pixels.

Uniform Types

JavaScript values are automatically converted to WGSL types.

TypeScript
// Scalar → f32
{ value: 0.5 }
 
// Vec2 → vec2f
{ value: [0.5, 0.5] }
 
// Vec3 → vec3f
{ value: [1.0, 0.5, 0.2] }
 
// Vec4 → vec4f
{ value: [1.0, 0.5, 0.2, 1.0] }
 
// Texture → texture_2d<f32> + sampler
{ value: renderTarget.texture }
Reactive updates: When you change a uniform's .value, the change is automatically uploaded to the GPU before the next draw call. No manual update needed.

Texture Bindings

ralph-gpu supports flexible ways to pass textures and samplers to shaders.

Binding Patterns

TypeScript
// Pattern 1: RenderTarget (convenience - auto-extracts texture + sampler)
const uniforms1 = {
  myTexture: { value: renderTarget },  // Easiest
};
 
// Pattern 2: Separate texture + custom sampler (explicit control)
const customSampler = ctx.createSampler({ magFilter: "nearest" });
const uniforms2 = {
  myTexture: { value: renderTarget.texture },
  mySampler: { value: customSampler },
};
 
// Pattern 3: Texture without sampler (for textureLoad in WGSL)
const uniforms3 = {
  dataTexture: { value: renderTarget.texture },  // No sampler needed
};
 
// In WGSL:
@group(1) @binding(0) var myTexture: texture_2d<f32>;
@group(1) @binding(1) var mySampler: sampler;  // Auto-matched by naming convention

Sampler Naming Convention

The system automatically matches samplers to textures:

  • myTexture → looks for myTextureSampler
  • inputTex → looks for inputSampler or inputTexSampler
  • someTexture → looks for someSampler or someTextureSampler

Compute Shaders with Textures

Compute shaders can now sample from textures for advanced GPU-accelerated effects.

TypeScript
// Compute shader with texture sampling
const compute = ctx.compute(`
  @group(1) @binding(0) var inputTex: texture_2d<f32>;
  @group(1) @binding(1) var inputSampler: sampler;
  @group(1) @binding(2) var<storage, read_write> output: array<f32>;
  
  @compute @workgroup_size(64)
  fn main(@builtin(global_invocation_id) id: vec3<u32>) {
    let uv = vec2f(f32(id.x) / 512.0, f32(id.y) / 512.0);
    let color = textureSampleLevel(inputTex, inputSampler, uv, 0.0);
    output[id.x] = color.r;
  }
`, {
  uniforms: {
    inputTex: { value: renderTarget },
  },
});
 
compute.storage("output", dataBuffer);
compute.dispatch(512);

Storage Textures (Write Operations)

Use storage textures to write directly to textures from compute shaders.

TypeScript
// Storage texture for compute shader writes
const outputTarget = ctx.target(512, 512, {
  format: "rgba16float",
  usage: "storage",  // Enable textureStore()
});
 
const compute = ctx.compute(`
  @group(1) @binding(0) var input: texture_2d<f32>;
  @group(1) @binding(1) var inputSampler: sampler;
  @group(1) @binding(2) var output: texture_storage_2d<rgba16float, write>;
  
  @compute @workgroup_size(8, 8)
  fn main(@builtin(global_invocation_id) id: vec3<u32>) {
    let uv = vec2f(id.xy) / 512.0;
    let color = textureSampleLevel(input, inputSampler, uv, 0.0);
    textureStore(output, id.xy, color * 2.0);  // Write to storage texture
  }
`, {
  uniforms: {
    input: { value: inputTarget },
    output: { value: outputTarget },
  },
});
 
compute.dispatch(512 / 8, 512 / 8);

Usage Modes

  • "render" (default) — For rendering and sampling
  • "storage" — For compute shader write operations
  • "both" — For both rendering and storage operations
Note: Storage textures don't require samplers — use textureStore() directly with pixel coordinates.

Error Types

ralph-gpu exports typed errors for better error handling.

TypeScript
import {
  WebGPUNotSupportedError,
  DeviceCreationError,
  ShaderCompileError,
} from "ralph-gpu";
 
try {
  const ctx = await gpu.init(canvas);
} catch (e) {
  if (e instanceof WebGPUNotSupportedError) {
    // Browser doesn't support WebGPU
    // navigator.gpu is undefined
  } else if (e instanceof DeviceCreationError) {
    // GPU device couldn't be created
    // May happen with unsupported hardware
  } else if (e instanceof ShaderCompileError) {
    // WGSL syntax error
    console.error(`Line ${e.line}, Col ${e.column}: ${e.message}`);
  }
}

WebGPUNotSupportedError

Thrown when navigator.gpu is undefined. The browser doesn't support WebGPU. Show a fallback UI.

DeviceCreationError

Thrown when the GPU device couldn't be created. May happen with unsupported hardware or driver issues.

ShaderCompileError

Thrown when WGSL code has syntax errors. Includes line, column, and message properties for debugging.

Next Steps