Skip to content

@typegpu/gl

@typegpu/gl lets TypeGPU generate GLSL and provides an experimental WebGL 2 backend for a subset of TypeGPU’s render API. It is useful when an application needs to run a render effect in browsers without WebGPU, or when TypeGPU shader functions need to be integrated into an existing WebGL renderer.

Refer to TypeGPU’s installation guide for setting up TypeGPU if you haven’t already. After that, install @typegpu/gl using the package manager of your choice.

npm install @typegpu/gl

Use initWithGLFallback in place of tgpu.init to try WebGPU first and fall back to WebGL 2 if WebGPU is unavailable or initialization fails.

import {
function initWithGLFallback(): Promise<TgpuRoot>
initWithGLFallback
} from '@typegpu/gl';
const
const root: TgpuRoot
root
= await
function initWithGLFallback(): Promise<TgpuRoot>
initWithGLFallback
();

The returned root exposes the common TypeGPU API, so a supported render pipeline does not need separate WebGPU and WebGL implementations. Let’s create a triangle whose color varies with its UV coordinates.

const
const positions: TgpuConst<d.WgslArray<d.Vec2f>>
positions
=
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
const: <d.WgslArray<d.Vec2f>>(dataType: d.WgslArray<d.Vec2f>, value: d.v2f[]) => TgpuConst<d.WgslArray<d.Vec2f>> (+1 overload)

Creates a module constant with specified value.

const
(
import d
d
.
arrayOf<d.Vec2f>(elementType: d.Vec2f, elementCount: number): d.WgslArray<d.Vec2f> (+1 overload)
export arrayOf

Creates an array schema that can be used to construct gpu buffers. Describes arrays with fixed-size length, storing elements of the same type.

@example

const LENGTH = 3; const array = d.arrayOf(d.u32, LENGTH);

If elementCount is not specified, a partially applied function is returned.

@example const array = d.arrayOf(d.vec3f); // ^? (n: number) => WgslArray<d.Vec3f>

@paramelementType The type of elements in the array.

@paramelementCount The number of elements in the array.

arrayOf
(
import d
d
.
const vec2f: d.Vec2f
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
, 3), [
import d
d
.
function vec2f(x: number, y: number): d.v2f (+3 overloads)
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
(0, 0.5),
import d
d
.
function vec2f(x: number, y: number): d.v2f (+3 overloads)
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
(-0.5, -0.5),
import d
d
.
function vec2f(x: number, y: number): d.v2f (+3 overloads)
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
(0.5, -0.5),
]);
const
const uvs: TgpuConst<d.WgslArray<d.Vec2f>>
uvs
=
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
const: <d.WgslArray<d.Vec2f>>(dataType: d.WgslArray<d.Vec2f>, value: d.v2f[]) => TgpuConst<d.WgslArray<d.Vec2f>> (+1 overload)

Creates a module constant with specified value.

const
(
import d
d
.
arrayOf<d.Vec2f>(elementType: d.Vec2f, elementCount: number): d.WgslArray<d.Vec2f> (+1 overload)
export arrayOf

Creates an array schema that can be used to construct gpu buffers. Describes arrays with fixed-size length, storing elements of the same type.

@example

const LENGTH = 3; const array = d.arrayOf(d.u32, LENGTH);

If elementCount is not specified, a partially applied function is returned.

@example const array = d.arrayOf(d.vec3f); // ^? (n: number) => WgslArray<d.Vec3f>

@paramelementType The type of elements in the array.

@paramelementCount The number of elements in the array.

arrayOf
(
import d
d
.
const vec2f: d.Vec2f
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
, 3), [
import d
d
.
function vec2f(x: number, y: number): d.v2f (+3 overloads)
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
(0.5, 1),
import d
d
.
function vec2f(x: number, y: number): d.v2f (+3 overloads)
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
(0, 0),
import d
d
.
function vec2f(x: number, y: number): d.v2f (+3 overloads)
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
(1, 0),
]);
const
const pipeline: TgpuRenderPipeline<d.Vec4f>
pipeline
=
const root: TgpuRoot
root
.
WithBinding.createRenderPipeline<Record<string, any>, {
[x: string]: any;
}, {
$position: d.v4f;
uv: d.v2f;
}, d.v4f>(descriptor: TgpuRenderPipeline<in Targets = never>.DescriptorBase & {
attribs?: {
[x: string]: any;
} | undefined;
vertex: TgpuVertexFn<Record<string, any>, TgpuVertexFn<in VertexIn extends TgpuVertexFn.In = Record<string, never>, out VertexOut extends TgpuVertexFn.Out = TgpuVertexFn.Out>.Out> | ((input: AutoVertexIn<InferGPURecord<AttribRecordToDefaultDataTypes<{
[x: string]: any;
}>>>) => AutoVertexOut<...>);
fragment: TgpuFragmentFn<...> | ((input: AutoFragmentIn<...>) => d.v4f);
targets?: TgpuColorTargetState;
}): TgpuRenderPipeline<...> (+2 overloads)
createRenderPipeline
({
vertex: TgpuVertexFn<Record<string, any>, TgpuVertexFn.Out> | ((input: AutoVertexIn<InferGPURecord<AttribRecordToDefaultDataTypes<{
[x: string]: any;
}>>>) => AutoVertexOut<{
$position: d.v4f;
uv: d.v2f;
}>)
vertex
: ({
$vertexIndex: number
$vertexIndex
:
index: number
index
}) => {
'use gpu';
return {
$position?: d.v4f | undefined
$position
:
import d
d
.
function vec4f(v0: AnyNumericVec2Instance, z: number, w: number): d.v4f (+9 overloads)
export vec4f

Schema representing vec4f - a vector with 4 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec4f(); // (0.0, 0.0, 0.0, 0.0) const vector = d.vec4f(1); // (1.0, 1.0, 1.0, 1.0) const vector = d.vec4f(1, 2, 3, 4.5); // (1.0, 2.0, 3.0, 4.5)

@example const buffer = root.createBuffer(d.vec4f, d.vec4f(0, 1, 2, 3)); // buffer holding a d.vec4f value, with an initial value of vec4f(0, 1, 2, 3);

vec4f
(
const positions: TgpuConst<d.WgslArray<d.Vec2f>>
positions
.
TgpuConst<WgslArray<Vec2f>>.$: readonly d.v2f[]
$
[
index: number
index
], 0, 1),
uv: d.v2f
uv
:
const uvs: TgpuConst<d.WgslArray<d.Vec2f>>
uvs
.
TgpuConst<WgslArray<Vec2f>>.$: readonly d.v2f[]
$
[
index: number
index
],
};
},
fragment: TgpuFragmentFn<{
uv: d.Vec2f;
} & Record<string, AnyFragmentInputBuiltin>, TgpuFragmentFn.Out> | ((input: AutoFragmentIn<InferGPURecord<{
uv: d.Vec2f;
}>>) => d.v4f)
fragment
: ({
uv: d.v2f
uv
}) => {
'use gpu';
return
import d
d
.
function vec4f(v0: AnyNumericVec2Instance, z: number, w: number): d.v4f (+9 overloads)
export vec4f

Schema representing vec4f - a vector with 4 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec4f(); // (0.0, 0.0, 0.0, 0.0) const vector = d.vec4f(1); // (1.0, 1.0, 1.0, 1.0) const vector = d.vec4f(1, 2, 3, 4.5); // (1.0, 2.0, 3.0, 4.5)

@example const buffer = root.createBuffer(d.vec4f, d.vec4f(0, 1, 2, 3)); // buffer holding a d.vec4f value, with an initial value of vec4f(0, 1, 2, 3);

vec4f
(
uv: d.v2f
uv
, 0.5, 1);
},
});

The vertex data is stored in TypeGPU constants rather than vertex buffers because the fallback backend does not currently support buffers.

Next, configure a canvas and draw the three vertices:

const canvas = document.querySelector('canvas') as HTMLCanvasElement;
const context = root.configureContext({
canvas,
alphaMode: 'premultiplied',
});
pipeline.withColorAttachment({ view: context }).draw(3);

The fallback renders on an internal OffscreenCanvas, then transfers the result to the configured canvas. This requires support for OffscreenCanvas, WebGL 2, and the bitmaprenderer canvas context.

Uniforms are the supported way to pass values that change without recompiling the shaders. Create them with root.createUniform, reference them through .$ in GPU code, and update them with .write().

const time = root.createUniform(d.f32);
const pipeline = root.createRenderPipeline({
vertex: ({ $vertexIndex: index }) => {
'use gpu';
return {
$position: d.vec4f(positions.$[index], 0, 1),
uv: uvs.$[index],
};
},
fragment: ({ uv }) => {
'use gpu';
return d.vec4f(uv, 0.5, 1);
return d.vec4f((uv + time.$) % 1, 0.5, 1);
},
});

Then write the time before each draw:

function draw(timestamp: number) {
time.write(timestamp * 0.001);
pipeline.withColorAttachment({ view: context }).draw(3);
requestAnimationFrame(draw);
}
requestAnimationFrame(draw);
import {
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
,
import d
d
} from 'typegpu';
import {
function initWithGLFallback(): Promise<TgpuRoot>
initWithGLFallback
} from '@typegpu/gl';
const
const root: TgpuRoot
root
= await
function initWithGLFallback(): Promise<TgpuRoot>
initWithGLFallback
();
const
const time: TgpuUniform<d.F32>
time
=
const root: TgpuRoot
root
.
TgpuRoot.createUniform<d.F32>(typeSchema: d.F32, initial?: number | ((buffer: TgpuBuffer<NoInfer<d.F32>>) => void) | undefined): TgpuUniform<d.F32> (+1 overload)

Allocates memory on the GPU, allows passing data between host and shader. Read-only on the GPU, optimized for small data. For a general-purpose buffer, use

TgpuRoot.createBuffer

.

@paramtypeSchema The type of data that this buffer will hold.

@paraminitial Either initial value of the buffer, or an initializer to execute on the mapped buffer. (optional)

createUniform
(
import d
d
.
const f32: d.F32
export f32

A schema that represents a 32-bit float value. (equivalent to f32 in WGSL)

Can also be called to cast a value to an f32.

@example const value = f32(); // 0

@example const value = f32(1.23); // 1.23

@example const value = f32(true); // 1

f32
);
const
const positions: TgpuConst<d.WgslArray<d.Vec2f>>
positions
=
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
const: <d.WgslArray<d.Vec2f>>(dataType: d.WgslArray<d.Vec2f>, value: d.v2f[]) => TgpuConst<d.WgslArray<d.Vec2f>> (+1 overload)

Creates a module constant with specified value.

const
(
import d
d
.
arrayOf<d.Vec2f>(elementType: d.Vec2f, elementCount: number): d.WgslArray<d.Vec2f> (+1 overload)
export arrayOf

Creates an array schema that can be used to construct gpu buffers. Describes arrays with fixed-size length, storing elements of the same type.

@example

const LENGTH = 3; const array = d.arrayOf(d.u32, LENGTH);

If elementCount is not specified, a partially applied function is returned.

@example const array = d.arrayOf(d.vec3f); // ^? (n: number) => WgslArray<d.Vec3f>

@paramelementType The type of elements in the array.

@paramelementCount The number of elements in the array.

arrayOf
(
import d
d
.
const vec2f: d.Vec2f
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
, 3), [
import d
d
.
function vec2f(x: number, y: number): d.v2f (+3 overloads)
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
(0, 0.5),
import d
d
.
function vec2f(x: number, y: number): d.v2f (+3 overloads)
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
(-0.5, -0.5),
import d
d
.
function vec2f(x: number, y: number): d.v2f (+3 overloads)
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
(0.5, -0.5),
]);
const
const uvs: TgpuConst<d.WgslArray<d.Vec2f>>
uvs
=
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
const: <d.WgslArray<d.Vec2f>>(dataType: d.WgslArray<d.Vec2f>, value: d.v2f[]) => TgpuConst<d.WgslArray<d.Vec2f>> (+1 overload)

Creates a module constant with specified value.

const
(
import d
d
.
arrayOf<d.Vec2f>(elementType: d.Vec2f, elementCount: number): d.WgslArray<d.Vec2f> (+1 overload)
export arrayOf

Creates an array schema that can be used to construct gpu buffers. Describes arrays with fixed-size length, storing elements of the same type.

@example

const LENGTH = 3; const array = d.arrayOf(d.u32, LENGTH);

If elementCount is not specified, a partially applied function is returned.

@example const array = d.arrayOf(d.vec3f); // ^? (n: number) => WgslArray<d.Vec3f>

@paramelementType The type of elements in the array.

@paramelementCount The number of elements in the array.

arrayOf
(
import d
d
.
const vec2f: d.Vec2f
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
, 3), [
import d
d
.
function vec2f(x: number, y: number): d.v2f (+3 overloads)
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
(0.5, 1),
import d
d
.
function vec2f(x: number, y: number): d.v2f (+3 overloads)
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
(0, 0),
import d
d
.
function vec2f(x: number, y: number): d.v2f (+3 overloads)
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
(1, 0),
]);
const
const pipeline: TgpuRenderPipeline<d.Vec4f>
pipeline
=
const root: TgpuRoot
root
.
WithBinding.createRenderPipeline<Record<string, any>, {
[x: string]: any;
}, {
$position: d.v4f;
uv: d.v2f;
}, d.v4f>(descriptor: TgpuRenderPipeline<in Targets = never>.DescriptorBase & {
attribs?: {
[x: string]: any;
} | undefined;
vertex: TgpuVertexFn<Record<string, any>, TgpuVertexFn<in VertexIn extends TgpuVertexFn.In = Record<string, never>, out VertexOut extends TgpuVertexFn.Out = TgpuVertexFn.Out>.Out> | ((input: AutoVertexIn<InferGPURecord<AttribRecordToDefaultDataTypes<{
[x: string]: any;
}>>>) => AutoVertexOut<...>);
fragment: TgpuFragmentFn<...> | ((input: AutoFragmentIn<...>) => d.v4f);
targets?: TgpuColorTargetState;
}): TgpuRenderPipeline<...> (+2 overloads)
createRenderPipeline
({
vertex: TgpuVertexFn<Record<string, any>, TgpuVertexFn.Out> | ((input: AutoVertexIn<InferGPURecord<AttribRecordToDefaultDataTypes<{
[x: string]: any;
}>>>) => AutoVertexOut<{
$position: d.v4f;
uv: d.v2f;
}>)
vertex
: ({
$vertexIndex: number
$vertexIndex
:
index: number
index
}) => {
'use gpu';
return {
$position?: d.v4f | undefined
$position
:
import d
d
.
function vec4f(v0: AnyNumericVec2Instance, z: number, w: number): d.v4f (+9 overloads)
export vec4f

Schema representing vec4f - a vector with 4 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec4f(); // (0.0, 0.0, 0.0, 0.0) const vector = d.vec4f(1); // (1.0, 1.0, 1.0, 1.0) const vector = d.vec4f(1, 2, 3, 4.5); // (1.0, 2.0, 3.0, 4.5)

@example const buffer = root.createBuffer(d.vec4f, d.vec4f(0, 1, 2, 3)); // buffer holding a d.vec4f value, with an initial value of vec4f(0, 1, 2, 3);

vec4f
(
const positions: TgpuConst<d.WgslArray<d.Vec2f>>
positions
.
TgpuConst<WgslArray<Vec2f>>.$: readonly d.v2f[]
$
[
index: number
index
], 0, 1),
uv: d.v2f
uv
:
const uvs: TgpuConst<d.WgslArray<d.Vec2f>>
uvs
.
TgpuConst<WgslArray<Vec2f>>.$: readonly d.v2f[]
$
[
index: number
index
],
};
},
fragment: TgpuFragmentFn<{
uv: d.Vec2f;
} & Record<string, AnyFragmentInputBuiltin>, TgpuFragmentFn.Out> | ((input: AutoFragmentIn<InferGPURecord<{
uv: d.Vec2f;
}>>) => d.v4f)
fragment
: ({
uv: d.v2f
uv
}) => {
'use gpu';
return
import d
d
.
function vec4f(v0: AnyNumericVec2Instance, z: number, w: number): d.v4f (+9 overloads)
export vec4f

Schema representing vec4f - a vector with 4 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec4f(); // (0.0, 0.0, 0.0, 0.0) const vector = d.vec4f(1); // (1.0, 1.0, 1.0, 1.0) const vector = d.vec4f(1, 2, 3, 4.5); // (1.0, 2.0, 3.0, 4.5)

@example const buffer = root.createBuffer(d.vec4f, d.vec4f(0, 1, 2, 3)); // buffer holding a d.vec4f value, with an initial value of vec4f(0, 1, 2, 3);

vec4f
((
uv: d.v2f
uv
+
const time: TgpuUniform<d.F32>
time
.
TgpuUniform<F32>.$: number
$
) % 1, 0.5, 1);
},
});
const
const canvas: HTMLCanvasElement
canvas
=
var document: Document

window.document returns a reference to the document contained in the window.

MDN Reference

document
.
ParentNode.querySelector<"canvas">(selectors: "canvas"): HTMLCanvasElement | null (+4 overloads)

Returns the first element that is a descendant of node that matches selectors.

MDN Reference

querySelector
('canvas') as
interface HTMLCanvasElement

The HTMLCanvasElement interface provides properties and methods for manipulating the layout and presentation of elements. The HTMLCanvasElement interface also inherits the properties and methods of the HTMLElement interface.

MDN Reference

HTMLCanvasElement
;
const
const context: GPUCanvasContext
context
=
const root: TgpuRoot
root
.
TgpuRoot.configureContext(options: ConfigureContextOptions): GPUCanvasContext

Creates and configures context for the provided canvas. Automatically sets the format to navigator.gpu.getPreferredCanvasFormat() if not provided.

@throwsAn error if no context could be obtained

configureContext
({
canvas: HTMLCanvasElement | OffscreenCanvas

The canvas for which a context will be created and configured.

canvas
,
alphaMode?: GPUCanvasAlphaMode | undefined

Determines the effect that alpha values will have on the content of textures returned by

GPUCanvasContext#getCurrentTexture

when read, displayed, or used as an image source.

alphaMode
: 'premultiplied',
});
let
let animationFrame: number
animationFrame
= 0;
function
function draw(timestamp: number): void
draw
(
timestamp: number
timestamp
: number) {
const time: TgpuUniform<d.F32>
time
.
TgpuBufferBindingBase<F32>.write(data: number, options?: BufferWriteOptions): void
write
(
timestamp: number
timestamp
* 0.001);
const pipeline: TgpuRenderPipeline<d.Vec4f>
pipeline
.
TgpuRenderPipeline<Vec4f>.withColorAttachment(attachment: ColorAttachment): TgpuRenderPipeline<d.Vec4f>

Attaches texture views to the pipeline's targets (outputs).

@example // Draw 3 vertices onto the context's canvas pipeline .withColorAttachment({ view: context }) .draw(3)

@paramattachment The object should match the shape returned by the fragment shader, with values matching the ColorAttachment type.

withColorAttachment
({
ColorAttachment.view: GPUCanvasContext | (ColorTextureConstraint & RenderFlag) | GPUTextureView | TgpuTextureView<d.WgslTexture<WgslTextureProps>> | TgpuTextureRenderView

A

GPUTextureView

describing the texture subresource that will be output to for this color attachment.

view
:
const context: GPUCanvasContext
context
}).
TgpuRenderPipeline<Vec4f>.draw(vertexCount: number, instanceCount?: number, firstVertex?: number, firstInstance?: number): void
draw
(3);
let animationFrame: number
animationFrame
=
function requestAnimationFrame(callback: FrameRequestCallback): number
requestAnimationFrame
(
function draw(timestamp: number): void
draw
);
}
let animationFrame: number
animationFrame
=
function requestAnimationFrame(callback: FrameRequestCallback): number
requestAnimationFrame
(
function draw(timestamp: number): void
draw
);
function
function cleanup(): void
cleanup
() {
function cancelAnimationFrame(handle: number): void
cancelAnimationFrame
(
let animationFrame: number
animationFrame
);
const root: TgpuRoot
root
.
TgpuRoot.destroy(): void

Destroys all underlying resources (i.e. buffers...) created through this root object. If the object is created via tgpu.init instead of tgpu.initFromDevice, then the inner GPU device is destroyed as well.

destroy
();
}

The fallback root is designed for shader-driven effects that can keep their geometry in constants and their changing state in uniforms.

FeatureWebGL 2 fallback
Vertex and fragment functionsSupported
TypeGPU constants and helper functionsSupported
UniformsSupported for scalar, floating-point vector, and floating-point matrix schemas
Non-indexed triangle drawsSupported
Vertex and index buffersNot supported
Textures and samplersNot supported
Bind groups, readonly buffers, and mutable buffersNot supported
Compute pipelinesNot supported
Command and render bundle encodersNot supported

Unsupported root operations throw an error explaining that the operation is unavailable in the WebGL fallback. When you need different resource strategies for WebGPU and WebGL, use isGLRoot after initialization.

The GLSL generator can also be used independently of the fallback root. Pass glOptions() to tgpu.resolve to resolve a TypeGPU function as GLSL instead of WGSL.

import {
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
,
import d
d
} from 'typegpu';
import {
function glOptions(): {
unstable_shaderGenerator: GlslGenerator;
}
glOptions
} from '@typegpu/gl';
const
const getColor: TgpuFn<(uv: d.Vec2f) => d.Vec4f>
getColor
=
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
fn: <[d.Vec2f], d.Vec4f>(argTypes: [d.Vec2f], returnType: d.Vec4f) => TgpuFnShell<[d.Vec2f], d.Vec4f> (+2 overloads)
fn
(
[
import d
d
.
const vec2f: d.Vec2f
export vec2f

Schema representing vec2f - a vector with 2 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec2f(); // (0.0, 0.0) const vector = d.vec2f(1); // (1.0, 1.0) const vector = d.vec2f(0.5, 0.1); // (0.5, 0.1)

@example const buffer = root.createBuffer(d.vec2f, d.vec2f(0, 1)); // buffer holding a d.vec2f value, with an initial value of vec2f(0, 1);

vec2f
],
import d
d
.
const vec4f: d.Vec4f
export vec4f

Schema representing vec4f - a vector with 4 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec4f(); // (0.0, 0.0, 0.0, 0.0) const vector = d.vec4f(1); // (1.0, 1.0, 1.0, 1.0) const vector = d.vec4f(1, 2, 3, 4.5); // (1.0, 2.0, 3.0, 4.5)

@example const buffer = root.createBuffer(d.vec4f, d.vec4f(0, 1, 2, 3)); // buffer holding a d.vec4f value, with an initial value of vec4f(0, 1, 2, 3);

vec4f
,
)((
uv: d.v2f
uv
) => {
'use gpu';
return
import d
d
.
function vec4f(v0: AnyNumericVec2Instance, z: number, w: number): d.v4f (+9 overloads)
export vec4f

Schema representing vec4f - a vector with 4 elements of type f32. Also a constructor function for this vector value.

@example const vector = d.vec4f(); // (0.0, 0.0, 0.0, 0.0) const vector = d.vec4f(1); // (1.0, 1.0, 1.0, 1.0) const vector = d.vec4f(1, 2, 3, 4.5); // (1.0, 2.0, 3.0, 4.5)

@example const buffer = root.createBuffer(d.vec4f, d.vec4f(0, 1, 2, 3)); // buffer holding a d.vec4f value, with an initial value of vec4f(0, 1, 2, 3);

vec4f
(
uv: d.v2f
uv
, 0.5, 1);
});
const
const glsl: string
glsl
=
const tgpu: {
const: typeof import("node_modules/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("node_modules/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("node_modules/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("node_modules/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("node_modules/typegpu/src/core/root/init").init;
initFromDevice: typeof import("node_modules/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("node_modules/typegpu/src/core/slot/slot").slot;
lazy: typeof import("node_modules/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("node_modules/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
resolve: (items: ResolvableObject[], options?: TgpuResolveOptions) => string (+1 overload)

A shorthand for calling tgpu.resolveWithContext(...).code.

@example

const Gradient = d.struct({ from: d.vec3f, to: d.vec3f });
const resolved = tgpu.resolve([Gradient]);
console.log(resolved);
// struct Gradient_0 {
// from: vec3f,
// to: vec3f,
// }

@example

const Gradient = d.struct({ from: d.vec3f, to: d.vec3f });
const code = tgpu.resolve({
template: `
fn getGradientAngle(gradient: Gradient) -> f32 {
return atan(gradient.to.y - gradient.from.y, gradient.to.x - gradient.from.x);
}
`,
externals: {
Gradient,
},
});
console.log(code);
// struct Gradient_0 {
// from: vec3f,
// to: vec3f,
// }
// fn getGradientAngle(gradient: Gradient_0) -> f32 {
// return atan(gradient.to.y - gradient.from.y, gradient.to.x - gradient.from.x);
// }

resolve
([
const getColor: TgpuFn<(uv: d.Vec2f) => d.Vec4f>
getColor
],
function glOptions(): {
unstable_shaderGenerator: GlslGenerator;
}
glOptions
());

For a vertex and fragment pair, use dualGlOptions(). Both stages share naming state, which keeps uniforms and inter-stage values consistent.

import { dualGlOptions } from '@typegpu/gl';
const options = dualGlOptions();
const vertexGlsl = tgpu.resolve([vertexFn, fragmentFn], options.vertex);
const fragmentGlsl = tgpu.resolve([vertexFn, fragmentFn], options.fragment);
const root = await initWithGLFallback();

Attempts to initialize the standard WebGPU root first. If WebGPU is unavailable or initialization fails, it creates a WebGL 2 root using an internal OffscreenCanvas.

Use this function when WebGPU is preferred and the effect only relies on the supported fallback API.

const root = initWithGL();

Creates a WebGL 2 root without attempting WebGPU. This is useful for testing the fallback path or deliberately targeting WebGL 2.

You can provide an existing WebGL 2 context, but it must belong to an OffscreenCanvas:

const offscreen = new OffscreenCanvas(1, 1);
const gl = offscreen.getContext('webgl2');
if (!gl) {
throw new Error('WebGL 2 is unavailable');
}
const root = initWithGL({ gl });

Calling initWithGL() without an argument creates the offscreen canvas and context for you.

if (isGLRoot(root)) {
// Use a fallback-compatible resource strategy.
} else {
// The root uses WebGPU.
}

Returns whether a root was created by the WebGL 2 backend. This is primarily useful after initWithGLFallback() when an application can use an optimized WebGPU path but still needs a fallback-compatible alternative.

const glsl = tgpu.resolve([resolvable], glOptions());

Returns resolution options that make TypeGPU generate GLSL for a single shader or helper-function graph.

const options = dualGlOptions();
const vertexGlsl = tgpu.resolve([vertexFn], options.vertex);
const fragmentGlsl = tgpu.resolve([fragmentFn], options.fragment);

Returns separate vertex and fragment resolution options backed by shared cross-stage state. Create one options object per shader pair and use each side for its corresponding stage.