Symbols in this topic
Gpu
The main API (vgpu) context returned by init(). It owns device lifetime and the frame clock; every resource — canvas surfaces, offscreen targets, render, compute, storage, uniforms, samplers, and bundles — is created by a free function that takes the Gpu as its first argument.
Import
import type { Gpu } from "vgpu";
import { init } from "vgpu/mock";Signature
import type { Bundle, BundleOptions, BundleRecorder, Clock, Compute, ComputeOptions, Draw, DrawOptions, Effect, EffectOptions, Frame, FrameLoopHandle, FrameLoopOptions, Geometry, GeometryOptions, GeometryRecipe, GpuErrorListener, PingPongStorage, PingPongTargets, SharedUniforms, StorageAccess, StorageBuffer, StorageOptions, Surface, SurfaceOptions, Target, TargetOptions, TargetTextureOptions, Timer, Visibility, VisibilityOptions } from "vgpu";
import type { Device } from "vgpu/core";
import type { ShaderSource } from "vgpu";
interface Gpu {
readonly device: Device;
readonly gpu: GPUDevice;
/** True once `dispose()` ran. Reads stay legal; new work does not. */
readonly disposed: boolean;
dispose(): void;
onError(cb: GpuErrorListener): () => void;
settled(): Promise<void>;
}
// The creation API: named exports of `vgpu`, `vgpu/node` and `vgpu/mock`, all gpu-first.
declare function surface(gpu: Gpu, canvas: HTMLCanvasElement | OffscreenCanvas, opts?: SurfaceOptions): Surface;
declare function effect(gpu: Gpu, source: string | ShaderSource, opts?: EffectOptions): Effect;
declare function draw(gpu: Gpu, opts: DrawOptions): Draw;
declare function target(gpu: Gpu, opts: TargetOptions): Target;
declare function frame(gpu: Gpu, cb?: (frame: Frame) => void): Frame;
declare function frameLoop(gpu: Gpu, cb: (frame: Frame) => void, opts?: FrameLoopOptions): FrameLoopHandle;
declare function sampler(gpu: Gpu, desc?: GPUSamplerDescriptor): GPUSampler;
declare function geometry(gpu: Gpu, input: GeometryOptions | GeometryRecipe): Geometry;
declare function compute(gpu: Gpu, source: string | ShaderSource, opts?: ComputeOptions): Compute;
declare function storage(gpu: Gpu, bytes: number, access?: StorageAccess | StorageOptions): StorageBuffer;
declare function timer(gpu: Gpu): Timer;
declare function visibility(gpu: Gpu, options?: VisibilityOptions): Visibility;
declare function pingPong(gpu: Gpu, width: number, height: number, opts?: TargetTextureOptions): PingPongTargets;
declare function pingPongStorage(gpu: Gpu, bytes: number): PingPongStorage;
declare function uniforms<T extends Record<string, unknown>>(gpu: Gpu, values: T): SharedUniforms<T>;
declare function bundle(gpu: Gpu, opts: BundleOptions, record: (recorder: BundleRecorder) => void): Bundle;
declare function clock(gpu: Gpu): Clock;Parameters
Gpu is an object, not a callable constructor: it carries no creation methods. Every factory below takes it as gpu, its first argument.
| Param | Type | Required | Default | Notes |
|---|---|---|---|---|
| surface.canvas | HTMLCanvasElement | OffscreenCanvas | ✔ | — | Canvas-like object with a webgpu context. A canvas may have one live Surface. |
| surface.opts | SurfaceOptions | ✖ | {} | Per-surface canvas format, size, DPR, and auto-resize behavior. |
| effect.source | string | ShaderSource | ✔ | — | WGSL string or loader-produced ShaderSource { version: 1, wgsl }. |
| effect.opts | EffectOptions | ✖ | {} | label defaults to "effect"; set defaults to no initial bindings. |
| draw.opts | DrawOptions | ✔ | — | Includes required shader; see DrawOptions. |
| target.opts | TargetOptions | ✔ | — | Offscreen target options. size is required. |
| frame.cb | (frame: Frame) => void | ✖ | undefined | If provided, submits automatically in finally; if omitted, caller must call frame.submit(). |
| sampler.desc | GPUSamplerDescriptor | ✖ | undefined | Cached by descriptor. sampler(gpu) is the canonical default sampler. |
| geometry.input | `GeometryOptions \ | GeometryRecipe` | ✔ | — |
| compute.source | string | ShaderSource | ✔ | — | WGSL string or ShaderSource. Must contain a @compute entry point. |
| compute.opts | ComputeOptions | ✖ | {} | label defaults to "compute"; set defaults to no initial bindings. |
| storage.bytes | number | ✔ | — | Byte size for a main API (vgpu) storage buffer. |
| storage.access | StorageAccess | StorageOptions | ✖ | "read-write" | Access string, or a StorageOptions bag { access?, indirect? }. See Compute for storage buffer semantics, including { indirect: true } for GPU-driven draw/dispatch arguments. |
| timer | — | — | — | No parameters. GPU pass timing; needs the "timestamp-query" device feature. See Timer for feature gating, spans, and result delivery. |
| visibility.options | VisibilityOptions | ✖ | {} | Occlusion queries for visibility culling — core WebGPU, no device feature required. See Visibility for capacity and handle semantics. |
| pingPong.width | number | ✔ | — | Floored and clamped to at least 1. |
| pingPong.height | number | ✔ | — | Floored and clamped to at least 1. |
| pingPong.opts | TargetTextureOptions | ✖ | {} | Texture/attachment options only; size comes from positional width/height. |
| pingPongStorage.bytes | number | ✔ | — | Creates two "read-write" storage buffers. |
| uniforms.values | Record<string, unknown> | ✔ | — | Cloned initial JS values; WGSL layout is adopted when first bound. |
| bundle.opts | BundleOptions | ✔ | — | Requires a target or target signature. |
| bundle.cb | (recorder: BundleRecorder) => void | ✔ | — | Records bundle commands immediately. |
| onError.cb | GpuErrorListener | ✔ | — | Receives asynchronous vgpu errors; returns an unsubscribe function. |
| clock | — | — | — | No parameters. The frame clock of this gpu: { time, deltaTime, frameCount, advance(dtSeconds) }, one instance per gpu. See Clock. |
Returns: each factory returns the resource named in its signature. dispose() and frame/pass callbacks return void.
Throws: VGPU-GPU-DISPOSED when any factory (or clock(gpu)) runs after gpu.dispose() — the device and everything it owned are gone, so the handle it would return could only fail later; create resources before disposing, or init() a new gpu; VGPU-GPU-FOREIGN when the first argument was not created by init() (a plain object, a GPUDevice, a gpu from another library): it carries no vgpu kernel, so pass the object returned by init() from vgpu, vgpu/node or vgpu/mock; VGPU-LIMIT-STORAGE-VERTEX / VGPU-LIMIT-STORAGE-FRAGMENT when a selected render entry exceeds its granted storage-buffer limit. The structured detail reports stage, entryPoint, count, limit, and each counted binding's name, group, and binding; request a supported limit or reduce/move the data; VGPU-SHADER-SOURCE-INVALID for malformed ShaderSource; VGPU-SET-TEXTURE-FILTERABILITY when a known facade texture format cannot satisfy an ordinarily sampled float binding (detail reports format, texture binding/name/label, and paired sampler identity); VGPU-RING1-UNSUPPORTED for unsupported effect/compute/target cases; VGPU-TARGET-REQUIRED when one-shot drawing needs an explicit target; VGPU-TARGET-SIZE-REQUIRED for runtime JS calls to target(gpu) without size; VGPU-SURFACE-* errors from surface(), surface resize, surface readback, or using disposed surfaces; plus method-specific VGPU-R1-*, VGPU-R3-*, and VGPU-R4-* errors documented on Effect, Draw, Compute, Frame, Bundle, Target, and SharedUniforms.
Examples
import { init, draw, frame, target } from "vgpu/mock";
const gpu = await init();
const colorTarget = target(gpu, { size: [128, 128], depth: true });
const drawable = draw(gpu, {
shader: `
@vertex fn vs_main(@builtin(vertex_index) vi: u32) -> @builtin(position) vec4f {
var p = array<vec2f, 3>(vec2f(-1, -1), vec2f(3, -1), vec2f(-1, 3));
return vec4f(p[vi], 0, 1);
}
@fragment fn fs_main() -> @location(0) vec4f { return vec4f(1, 0, 1, 1); }
`,
// optional sync pre-warm; `await draw.compile(target)` is preferred during browser load
targets: [colorTarget],
});
frame(gpu, (currentFrame) => {
currentFrame.pass({ target: colorTarget, clear: [0, 0, 0, 1] }, (pass) => pass.draw(drawable));
});import { init, effect, frameLoop, surface } from "vgpu";
declare const canvas: HTMLCanvasElement;
const gpu = await init();
const canvasSurface = surface(gpu, canvas, { dpr: [1, 2] });
const wave = effect(gpu, `@fragment fn fs_main() -> @location(0) vec4f { return vec4f(0.2, 0.4, 1.0, 1.0); }`);
frameLoop(gpu, (frame) => {
frame.pass({ target: canvasSurface }, (pass) => pass.draw(wave));
});Error delivery
gpu.onError(cb) subscribes to asynchronous vgpu errors and returns an unsubscribe function. Listeners run in subscription order; removing one stops future deliveries; a throwing listener is reported to console.error without stopping the rest. If no listener is registered, vgpu reports the error to console.error by default.
gpu.settled() resolves after the current snapshot of pending error deliveries and in-flight pipeline work settles. It never rejects, so it is safe for deterministic tests and teardown.
Notes
- There is no implicit screen property and no implicit default target. Pass
targetexplicitly to frame passes and one-shot draws. - Canvas-specific
size,dpr, andautoResizelive onsurface(gpu, canvas, opts), not oninit(). - Time is explicit JS state, and it lives on the clock, not on the context: read
clock(gpu).time/.deltaTime/.frameCountand pass them throughset()orSharedUniformswhen shaders need them. - Every factory rejects a disposed gpu with
VGPU-GPU-DISPOSED, and an object vgpu did not create withVGPU-GPU-FOREIGN. Both are thrown synchronously, from the call that made the mistake. - See also:
init,Clock,Surface,Effect,Draw,Compute,Frame,Target,Bundle,SharedUniforms,Timer,Visibility.
Sampled float texture layouts
vgpu infers sampled-texture layouts per selected WGSL entry point. A non-multisampled texture_*<f32> used by textureSample* or textureGather* with an ordinary sampler receives WebGPU sampleType: "float"; a texture used only by textureLoad remains "unfilterable-float". Calls through helper functions are included.
The WGSL f32 scalar type does not make every concrete texture format filterable. In particular, r32float, rg32float, and rgba32float require the device's float32-filterable feature for ordinary sampling. Use a filterable format, request that feature when supported, or use textureLoad without a sampler.