Skip to content

Uniform Module API Reference

This document covers the exports from src/uniform/: the UniformBuffer implementation, supporting interfaces, and the UniformUtils helper class.

Types & interfaces

UniformData

type UniformData = ArrayBufferView | ArrayBuffer;

Any typed array (e.g., Float32Array, Uint32Array, DataView) or raw ArrayBuffer can be passed to the UniformBuffer constructor.

IUniformBuffer

interface IUniformBuffer {
  readonly buffer: GPUBuffer;
  readonly bindGroup: GPUBindGroup;
  readonly size: number;
  readonly label?: string;
  readonly data: ArrayBuffer;
  setData(view: ArrayBufferView): void;
  flush(device?: GPUDevice): void;
  clone(device?: GPUDevice): IUniformBuffer;
  destroy(): void;
}

UniformBuffer implements this interface.

UniformConfig

interface UniformConfig {
  device: GPUDevice;
  data: UniformData;
  label?: string;
  usage?: GPUBufferUsageFlags; // optional extra usage bits
}

The current implementation takes (device, data, label?), but the config interface is exported for future pooling/usage overrides.

Class: UniformBuffer

class UniformBuffer implements IUniformBuffer {
  constructor(device: GPUDevice, init: UniformData, label?: string);

  static bindGroupLayout(device: GPUDevice): GPUBindGroupLayout;

  readonly buffer: GPUBuffer;
  readonly bindGroup: GPUBindGroup;
  readonly label?: string;
  readonly size: number;
  get data(): ArrayBuffer;
  set dataBytes(bytes: ArrayBuffer);
  setData(view: ArrayBufferView): void;
  flush(device?: GPUDevice): void;
  clone(device?: GPUDevice): UniformBuffer;
  destroy(): void;
}

Constructor

  • Copies the initial data into an internal ArrayBuffer cache.
  • Allocates a GPU buffer with GPUBufferUsage.UNIFORM | GPUBufferUsage.COPY_DST.
  • Writes the initial bytes to the GPU and creates a bind group using the shared layout.

static bindGroupLayout(device)

Returns (and lets WebGPU cache) the canonical uniform bind group layout:

entry: {
  binding: 0,
  visibility: GPUShaderStage.VERTEX | GPUShaderStage.FRAGMENT | GPUShaderStage.COMPUTE,
  buffer: { type: 'uniform' },
}

setData(view)

Copies a typed array into the CPU cache. Throws if view.byteLength !== size.

flush(device?)

Uploads the cached bytes to the GPU via queue.writeBuffer. If no device is provided it uses the one stored from construction.

data / dataBytes

  • data returns a cloned ArrayBuffer of the cache (for debugging or serialization).
  • dataBytes = newBytes replaces the cache entirely (size must match).

clone(device?)

Constructs a new UniformBuffer with the same bytes (useful when duplicating per-camera uniforms).

destroy()

Calls buffer.destroy(); does not null the bind group (caller manages references).

Class: UniformUtils

class UniformUtils {
  static alignSize(size: number): number;
  static createAlignedBuffer(size: number): ArrayBuffer;
  static packFloat32Array(values: number[], targetSize?: number): Float32Array;
  static packVec(values: number[], vecSize: 2 | 3 | 4): Float32Array;
  static packMat4(matrix: Float32Array | number[]): Float32Array;
}
  • alignSize �?rounds up to the next multiple of 16 bytes.
  • createAlignedBuffer �?returns an ArrayBuffer already aligned (zero-filled).
  • packFloat32Array �?writes an array of numbers into a Float32Array of a given length (padding with zeros if needed).
  • packVec �?handles vec2/vec3/vec4 padding (vec3 promoted to vec4).
  • packMat4 �?ensures the input has 16 elements and returns a column-major Float32Array (pass an existing Float32Array to avoid copies).

Usage snippets

Creating and binding a uniform

import { UniformBuffer } from 'src/uniform';

const projBytes = new Float32Array(16); // 64 bytes
const projUniform = new UniformBuffer(device, projBytes, 'projection');

renderPass.setBindGroup(0, projUniform.bindGroup);

Updating per frame

function updateCamera(cameraBytes: Float32Array) {
  cameraUniform.setData(cameraBytes);
  cameraUniform.flush();
}

Packing structs

const settingsData = new Float32Array(20); // 80 bytes
// Fill clipping boxes, scaling, etc.
settingsUniform.setData(settingsData);
settingsUniform.flush();

Cloning for multiple cameras

const mainCam = new UniformBuffer(device, mainData, 'main-camera');
const debugCam = mainCam.clone();

Notes

  • Every UniformBuffer keeps its own CPU cache. If you need to share bytes between buffers, write to the cache once (setData) and call clone().
  • All helpers assume WebGPU’s 16-byte alignment. When constructing structs manually, prefer UniformUtils.createAlignedBuffer to avoid off-by-one mistakes.
  • The module does not automatically flush; callers decide when GPU uploads happen so they can batch updates before encoding passes.