Skip to content

Data Schemas

GPU programs usually involve sharing data between the host (CPU) and the device (GPU). In the case of WebGPU, even though data is strongly typed in WGSL shaders, the communication between JavaScript and WGSL involves reading raw bytes from buffers. Any misalignments or misinterpretations of data can lead to faulty code that is difficult to debug. This is precisely what TypeGPU data schemas, like d.u32 or d.vec3f, help with.

The primary usage for data schemas is to define buffer and function signatures. Schemas can also be called in JS or TGSL to create instances of the types they represent.

TypeGPU provides data schemas for scalar, vector and matrix types, as well as constructors for struct and array schemas.

For scalar WGSL types f32, u32, i32, f16 and bool, TypeGPU provides d.f32, d.u32, d.i32, d.f16 and d.bool schemas respectively. Schemas can be called to cast a value to a given type. This works both in TGSL, and in plain JavaScript.

import d
d
.
function u32(v?: number | boolean): number
export u32

A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)

Can also be called to cast a value to an u32 in accordance with WGSL casting rules.

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

@example const value = u32(7); // 7

@example const value = u32(3.14); // 3

@example const value = u32(-1); // 4294967295

@example const value = u32(-3.1); // 0

u32
(31.1); // 31
import d
d
.
function u32(v?: number | boolean): number
export u32

A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)

Can also be called to cast a value to an u32 in accordance with WGSL casting rules.

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

@example const value = u32(7); // 7

@example const value = u32(3.14); // 3

@example const value = u32(-1); // 4294967295

@example const value = u32(-3.1); // 0

u32
(-1); // 4294967295
import d
d
.
function f32(v?: number | boolean): number
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
(true); // 1
import d
d
.
function i32(v?: number | boolean): number
export i32

A schema that represents a signed 32-bit integer value. (equivalent to i32 in WGSL)

Can also be called to cast a value to an i32 in accordance with WGSL casting rules.

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

@example const value = i32(3.14); // 3

@example const value = i32(-3.9); // -3

@example const value = i32(10000000000) // 1410065408

i32
(); // 0 (default value)
import d
d
.
function bool(v?: number | boolean): boolean
export bool

A schema that represents a boolean value. (equivalent to bool in WGSL)

Can also be called to cast a value to a bool in accordance with WGSL casting rules.

@example const value = bool(); // false

@example const value = bool(0); // false

@example const value = bool(-0); // false

@example const value = bool(21.37); // true

bool
(0.01); // true

For each of the scalar types, there is a vector schema of 2, 3 and 4 elements of that type. For vector WGSL types vec2f, vec2u, vec2i, vec2h and vec2<bool>, TypeGPU provides d.vec2f, d.vec2u, d.vec2i, d.vec2h and d.vec2b schemas respectively. Analogously for 3 and 4 components.

Just like scalar schemas, vector schemas can be called to create values of corresponding types.

const v1 =
import d
d
.
function vec3f(x: number, y: number, z: number): d.v3f (+5 overloads)
export vec3f

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

@example const vector = d.vec3f(); // (0.0, 0.0, 0.0) const vector = d.vec3f(1); // (1.0, 1.0, 1.0) const vector = d.vec3f(1, 2, 3.5); // (1.0, 2.0, 3.5)

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

vec3f
(1, 2, 3); // a vector of three elements [1, 2, 3]
const v1: d.v3f
const
const v2: d.v4f
v2
=
import d
d
.
function vec4f(x: number, y: number, 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 v1: d.v3f
v1
.
v3f.x: number
x
,
const v1: d.v3f
v1
[1], 4, 5); // a vector of four elements [1, 2, 4, 5]
const
const v3: d.v2f
v3
=
const v1: d.v3f
v1
.
Swizzle2<v2f, v3f, v4f>.xy: d.v2f
xy
; // a vector of two elements [1, 2]
const
const v4: d.v4f
v4
=
import d
d
.
function vec4f(x: number, v0: AnyNumericVec2Instance, z: 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
(0,
const v3: d.v2f
v3
, 3); // a vector of four elements [0, 1, 2, 3]

Matrices work similarly. For matrix WGSL types mat2x2f, mat3x3f and mat4x4f, TypeGPU provides d.mat2x2f, d.mat3x3f and d.mat4x4f schemas respectively. Matrices of other sizes, as well as matrices of f16, are currently not supported by TypeGPU.

const mat1 =
import d
d
.
function mat2x2f(): d.m2x2f (+2 overloads)
export mat2x2f

Schema representing mat2x2f - a matrix with 2 rows and 2 columns, with elements of type f32. Also a constructor function for this matrix type.

@example const zero2x2 = mat2x2f(); // filled with zeros

@example const mat = mat2x2f(0, 1, 2, 3); mat.columns[0] // vec2f(0, 1) mat.columns[1] // vec2f(2, 3)

@example const mat = mat2x2f( vec2f(0, 1), // column 0 vec2f(1, 2), // column 1 );

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

mat2x2f
(); // empty matrix
const mat1: d.m2x2f
const mat2 =
import d
d
.
function mat3x3f(elements_0: number, elements_1: number, elements_2: number, elements_3: number, elements_4: number, elements_5: number, elements_6: number, elements_7: number, elements_8: number): d.m3x3f (+2 overloads)
export mat3x3f

Schema representing mat3x3f - a matrix with 3 rows and 3 columns, with elements of type f32. Also a constructor function for this matrix type.

@example const zero3x3 = mat3x3f(); // filled with zeros

@example const mat = mat3x3f(0, 1, 2, 3, 4, 5, 6, 7, 8); mat.columns[0] // vec3f(0, 1, 2) mat.columns[1] // vec3f(3, 4, 5) mat.columns[2] // vec3f(6, 7, 8)

@example const mat = mat3x3f( vec3f(0, 1, 2), // column 0 vec3f(2, 3, 4), // column 1 vec3f(5, 6, 7), // column 2 );

@example const buffer = root.createBuffer(d.mat3x3f, d.mat3x3f()); // buffer holding a d.mat3x3f value, with an initial value of mat3x3f filled with zeros

mat3x3f
(
const mat2: d.m3x3f
1.1, 2.5, 3.3,
1.2, 2.6, 3.4,
1.3, 2.7, 3.5,
);
const firstColumn =
const mat2: d.m3x3f
mat2
.
mat3x3<v3f>.columns: readonly [d.v3f, d.v3f, d.v3f]
columns
[0]; // d.vec3f(1.1, 2.5, 3.3)
const firstColumn: d.v3f

As you may know, it is currently impossible to overload operators in JavaScript. For that reason, TypeGPU provides std functions imitating those.

import * as
import d
d
from 'typegpu/data';
import * as
import std
std
from 'typegpu/std';
const
const vec1: d.v3f
vec1
=
import d
d
.
function vec3f(x: number, y: number, z: number): d.v3f (+5 overloads)
export vec3f

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

@example const vector = d.vec3f(); // (0.0, 0.0, 0.0) const vector = d.vec3f(1); // (1.0, 1.0, 1.0) const vector = d.vec3f(1, 2, 3.5); // (1.0, 2.0, 3.5)

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

vec3f
(1, 2, 3);
const vec2 =
import std
std
.
add<d.v3f>(lhs: d.v3f, rhs: number): d.v3f (+4 overloads)
export add
add
(
const vec1: d.v3f
vec1
, 3); // d.vec3f(4, 5, 6)
const vec2: d.v3f
const
const mat: d.m3x3f
mat
=
import d
d
.
function mat3x3f(elements_0: number, elements_1: number, elements_2: number, elements_3: number, elements_4: number, elements_5: number, elements_6: number, elements_7: number, elements_8: number): d.m3x3f (+2 overloads)
export mat3x3f

Schema representing mat3x3f - a matrix with 3 rows and 3 columns, with elements of type f32. Also a constructor function for this matrix type.

@example const zero3x3 = mat3x3f(); // filled with zeros

@example const mat = mat3x3f(0, 1, 2, 3, 4, 5, 6, 7, 8); mat.columns[0] // vec3f(0, 1, 2) mat.columns[1] // vec3f(3, 4, 5) mat.columns[2] // vec3f(6, 7, 8)

@example const mat = mat3x3f( vec3f(0, 1, 2), // column 0 vec3f(2, 3, 4), // column 1 vec3f(5, 6, 7), // column 2 );

@example const buffer = root.createBuffer(d.mat3x3f, d.mat3x3f()); // buffer holding a d.mat3x3f value, with an initial value of mat3x3f filled with zeros

mat3x3f
(
2, 0, 0,
0, 4, 0,
0, 0, 8,
);
const multiplication =
import std
std
.
mul<d.m3x3f, d.v3f>(lhs: d.v3f, rhs: d.m3x3f): d.v3f (+7 overloads)
export mul
mul
(
const vec2: d.v3f
vec2
,
const mat: d.m3x3f
mat
); // d.vec3f(8, 20, 48);
const multiplication: d.v3f
const comparison =
import std
std
.
le<d.v3f>(lhs: d.v3f, rhs: d.v3f): d.v3b
export le

Checks component-wise whether lhs <= rhs. This function does not return bool, for that use-case, wrap the result in all.

@example le(vec2f(0.0, 0.0), vec2f(0.0, 1.0)) // returns vec2b(true, true) le(vec3u(0, 1, 2), vec3u(2, 1, 0)) // returns vec3b(true, true, false) all(le(vec4i(1, 2, 3, 4), vec4i(2, 3, 3, 5))) // returns true

le
(
import d
d
.
function vec3f(x: number, y: number, z: number): d.v3f (+5 overloads)
export vec3f

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

@example const vector = d.vec3f(); // (0.0, 0.0, 0.0) const vector = d.vec3f(1); // (1.0, 1.0, 1.0) const vector = d.vec3f(1, 2, 3.5); // (1.0, 2.0, 3.5)

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

vec3f
(2, 3, 4),
import d
d
.
function vec3f(xyz: number): d.v3f (+5 overloads)
export vec3f

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

@example const vector = d.vec3f(); // (0.0, 0.0, 0.0) const vector = d.vec3f(1); // (1.0, 1.0, 1.0) const vector = d.vec3f(1, 2, 3.5); // (1.0, 2.0, 3.5)

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

vec3f
(3)); // d.vec3b(true, true, false)
const comparison: d.v3b

Currently, implemented operators include:

  • arithmetic operators add, sub, mul, div, mod, neg,
  • comparison operators eq, ne, lt, le, gt, ge,
  • logical operators not, and, or.

When operating on scalars, you can still use +, <=, ! etc., the purpose of these std functions is to enable working on vectors and matrices.

For arithmetic operators, you can also use the infix notation.

const
const v1: d.v2f
v1
=
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, 2);
const
const v2: d.v2f
v2
=
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
(3, 4);
const
const addition: d.v2f
addition
=
const v1: d.v2f
v1
.
vecInfixNotation<v2f>.add(other: d.v2f): d.v2f (+1 overload)
add
(
const v2: d.v2f
v2
); // same as std.add(v1, v2)
const
const multiplication: d.v2f
multiplication
=
const v1: d.v2f
v1
.
vecInfixNotation<v2f>.mul(other: d.v2f): d.v2f (+2 overloads)
mul
(
const v2: d.v2f
v2
).
vecInfixNotation<v2f>.mul(other: number): d.v2f (+2 overloads)
mul
(3); // same as std.mul(std.mul(v1, v2), 3)

Here is an example of defining a custom compound data type using the d.struct function.

import * as
import d
d
from 'typegpu/data';
const
const Circle: d.WgslStruct<{
centerPos: d.Vec3i;
radius: d.F32;
}>
Circle
=
import d
d
.
struct<{
centerPos: d.Vec3i;
radius: d.F32;
}>(props: {
centerPos: d.Vec3i;
radius: d.F32;
}): d.WgslStruct<{
centerPos: d.Vec3i;
radius: d.F32;
}>
export struct

Creates a struct schema that can be used to construct GPU buffers. Ensures proper alignment and padding of properties (as opposed to a d.unstruct schema). The order of members matches the passed in properties object.

@example const CircleStruct = d.struct({ radius: d.f32, pos: d.vec3f });

@paramprops Record with string keys and TgpuData values, each entry describing one struct member.

struct
({
centerPos: d.Vec3i
centerPos
:
import d
d
.
const vec3i: d.Vec3i
export vec3i

Schema representing vec3i - a vector with 3 elements of type i32. Also a constructor function for this vector value.

@example const vector = d.vec3i(); // (0, 0, 0) const vector = d.vec3i(1); // (1, 1, 1) const vector = d.vec3i(1, 2, -3); // (1, 2, -3)

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

vec3i
,
radius: d.F32
radius
:
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 redCircle: {
centerPos: d.v3i;
radius: number;
}
redCircle
=
const Circle: d.WgslStruct
(props: {
centerPos: d.v3i;
radius: number;
}) => {
centerPos: d.v3i;
radius: number;
} (+1 overload)
Circle
({
centerPos: d.v3i
centerPos
:
import d
d
.
function vec3i(x: number, y: number, z: number): d.v3i (+5 overloads)
export vec3i

Schema representing vec3i - a vector with 3 elements of type i32. Also a constructor function for this vector value.

@example const vector = d.vec3i(); // (0, 0, 0) const vector = d.vec3i(1); // (1, 1, 1) const vector = d.vec3i(1, 2, -3); // (1, 2, -3)

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

vec3i
(2, 4, 0),
radius: number
radius
: 0.2,
});

If you’re familiar with Zod, then this style of schema definitions may already seem familiar. We define the Circle struct, similarly to how we would in WGSL, and then we can use it to validate and cast our data values. When reading from or writing data to the GPU, the type of the JavaScript value is inferred automatically.

const
const redCircle1: {
centerPos: d.v3i;
radius: number;
}
redCircle1
=
const Circle: d.WgslStruct
(props: {
centerPos: d.v3i;
radius: number;
}) => {
centerPos: d.v3i;
radius: number;
} (+1 overload)
Circle
({
centerPos:
import d
d
.
function vec2i(x: number, y: number): d.v2i (+3 overloads)
export vec2i

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

@example const vector = d.vec2i(); // (0, 0) const vector = d.vec2i(1); // (1, 1) const vector = d.vec2i(-1, 1); // (-1, 1)

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

vec2i
(2, 4),
Error ts(2740) ― Type 'v2i' is missing the following properties from type 'v3i': z, 2, xz, yz, and 87 more.
radius: number
radius
: 0.2,
});
const
const redCircle2: {
centerPos: d.v3i;
radius: number;
}
redCircle2
=
const Circle: d.WgslStruct
(props: {
centerPos: d.v3i;
radius: number;
}) => {
centerPos: d.v3i;
radius: number;
} (+1 overload)
Circle
({
centerPos: d.v3i
centerPos
:
import d
d
.
function vec3i(x: number, y: number, z: number): d.v3i (+5 overloads)
export vec3i

Schema representing vec3i - a vector with 3 elements of type i32. Also a constructor function for this vector value.

@example const vector = d.vec3i(); // (0, 0, 0) const vector = d.vec3i(1); // (1, 1, 1) const vector = d.vec3i(1, 2, -3); // (1, 2, -3)

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

vec3i
(2, 4, 0),
radius: "0.2",
Error ts(2322) ― Type 'string' is not assignable to type 'number'.
});
const
const redCircle3: {
centerPos: d.v3i;
radius: number;
}
redCircle3
=
const Circle: d.WgslStruct
(props: {
centerPos: d.v3i;
radius: number;
}) => {
centerPos: d.v3i;
radius: number;
} (+1 overload)
Circle
({
Error ts(2345) ― Argument of type '{ centerPos: d.v3i; }' is not assignable to parameter of type '{ centerPos: v3i; radius: number; }'. Property 'radius' is missing in type '{ centerPos: d.v3i; }' but required in type '{ centerPos: v3i; radius: number; }'.
centerPos: d.v3i
centerPos
:
import d
d
.
function vec3i(x: number, y: number, z: number): d.v3i (+5 overloads)
export vec3i

Schema representing vec3i - a vector with 3 elements of type i32. Also a constructor function for this vector value.

@example const vector = d.vec3i(); // (0, 0, 0) const vector = d.vec3i(1); // (1, 1, 1) const vector = d.vec3i(1, 2, -3); // (1, 2, -3)

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

vec3i
(2, 4, 0),
});
const
const diam: number
diam
=
const redCircle1: {
centerPos: d.v3i;
radius: number;
}
redCircle1
.rad * 2;
Error ts(2339) ― Property 'rad' does not exist on type '{ centerPos: v3i; radius: number; }'.

Struct schemas also allow for default value creation and code autocompletion.

const
const defaultBoid: {
position: d.v3u;
velocity: d.v3f;
color: d.v4f;
isActive: boolean;
}
defaultBoid
=
const Boid: d.WgslStruct
() => {
position: d.v3u;
velocity: d.v3f;
color: d.v4f;
isActive: boolean;
} (+1 overload)
Boid
(); // zero-filled boid
const
const boid: {
position: d.v3u;
velocity: d.v3f;
color: d.v4f;
isActive: boolean;
}
boid
=
const Boid: d.WgslStruct
(props: {
position: d.v3u;
velocity: d.v3f;
color: d.v4f;
isActive: boolean;
}) => {
position: d.v3u;
velocity: d.v3f;
color: d.v4f;
isActive: boolean;
} (+1 overload)
Boid
({
position: d.v3u
position
:
import d
d
.
function vec3u(x: number, y: number, z: number): d.v3u (+5 overloads)
export vec3u

Schema representing vec3u - a vector with 3 elements of type u32. Also a constructor function for this vector value.

@example const vector = d.vec3u(); // (0, 0, 0) const vector = d.vec3u(1); // (1, 1, 1) const vector = d.vec3u(1, 2, 3); // (1, 2, 3)

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

vec3u
(0, 0, 0),
velocity: d.v3f
velocity
:
import d
d
.
function vec3f(x: number, y: number, z: number): d.v3f (+5 overloads)
export vec3f

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

@example const vector = d.vec3f(); // (0.0, 0.0, 0.0) const vector = d.vec3f(1); // (1.0, 1.0, 1.0) const vector = d.vec3f(1, 2, 3.5); // (1.0, 2.0, 3.5)

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

vec3f
(1, 0.5, 0.5),
color: d.v4f
color
:
import d
d
.
function vec4f(x: number, y: number, 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
(1.0, 0.2, 0.3, 1.0),
isAct
isAct: any
isActive
});

Structs can also be nested.

const
const FishState: d.WgslStruct<{
pos: d.Vec3f;
vel: d.Vec3f;
}>
FishState
=
import d
d
.
struct<{
pos: d.Vec3f;
vel: d.Vec3f;
}>(props: {
pos: d.Vec3f;
vel: d.Vec3f;
}): d.WgslStruct<{
pos: d.Vec3f;
vel: d.Vec3f;
}>
export struct

Creates a struct schema that can be used to construct GPU buffers. Ensures proper alignment and padding of properties (as opposed to a d.unstruct schema). The order of members matches the passed in properties object.

@example const CircleStruct = d.struct({ radius: d.f32, pos: d.vec3f });

@paramprops Record with string keys and TgpuData values, each entry describing one struct member.

struct
({
pos: d.Vec3f
pos
:
import d
d
.
const vec3f: d.Vec3f
export vec3f

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

@example const vector = d.vec3f(); // (0.0, 0.0, 0.0) const vector = d.vec3f(1); // (1.0, 1.0, 1.0) const vector = d.vec3f(1, 2, 3.5); // (1.0, 2.0, 3.5)

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

vec3f
,
vel: d.Vec3f
vel
:
import d
d
.
const vec3f: d.Vec3f
export vec3f

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

@example const vector = d.vec3f(); // (0.0, 0.0, 0.0) const vector = d.vec3f(1); // (1.0, 1.0, 1.0) const vector = d.vec3f(1, 2, 3.5); // (1.0, 2.0, 3.5)

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

vec3f
,
});
const
const Fish: d.WgslStruct<{
kind: d.U32;
state: d.WgslStruct<{
pos: d.Vec3f;
vel: d.Vec3f;
}>;
}>
Fish
=
import d
d
.
struct<{
kind: d.U32;
state: d.WgslStruct<{
pos: d.Vec3f;
vel: d.Vec3f;
}>;
}>(props: {
kind: d.U32;
state: d.WgslStruct<{
pos: d.Vec3f;
vel: d.Vec3f;
}>;
}): d.WgslStruct<{
kind: d.U32;
state: d.WgslStruct<{
pos: d.Vec3f;
vel: d.Vec3f;
}>;
}>
export struct

Creates a struct schema that can be used to construct GPU buffers. Ensures proper alignment and padding of properties (as opposed to a d.unstruct schema). The order of members matches the passed in properties object.

@example const CircleStruct = d.struct({ radius: d.f32, pos: d.vec3f });

@paramprops Record with string keys and TgpuData values, each entry describing one struct member.

struct
({
kind: d.U32
kind
:
import d
d
.
const u32: d.U32
export u32

A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)

Can also be called to cast a value to an u32 in accordance with WGSL casting rules.

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

@example const value = u32(7); // 7

@example const value = u32(3.14); // 3

@example const value = u32(-1); // 4294967295

@example const value = u32(-3.1); // 0

u32
,
state: d.WgslStruct<{
pos: d.Vec3f;
vel: d.Vec3f;
}>
state
:
const FishState: d.WgslStruct<{
pos: d.Vec3f;
vel: d.Vec3f;
}>
FishState
, // nested struct
});
const instance =
const Fish: d.WgslStruct
(props: {
kind: number;
state: {
pos: d.v3f;
vel: d.v3f;
};
}) => {
kind: number;
state: {
pos: d.v3f;
vel: d.v3f;
};
} (+1 overload)
Fish
({
kind: number
kind
: 0,
state: {
pos: d.v3f;
vel: d.v3f;
}
state
: {
pos: d.v3f
pos
:
import d
d
.
function vec3f(): d.v3f (+5 overloads)
export vec3f

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

@example const vector = d.vec3f(); // (0.0, 0.0, 0.0) const vector = d.vec3f(1); // (1.0, 1.0, 1.0) const vector = d.vec3f(1, 2, 3.5); // (1.0, 2.0, 3.5)

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

vec3f
(),
vel: d.v3f
vel
:
import d
d
.
function vec3f(): d.v3f (+5 overloads)
export vec3f

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

@example const vector = d.vec3f(); // (0.0, 0.0, 0.0) const vector = d.vec3f(1); // (1.0, 1.0, 1.0) const vector = d.vec3f(1, 2, 3.5); // (1.0, 2.0, 3.5)

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

vec3f
() } });
const instance: {
kind: number;
state: {
pos: d.v3f;
vel: d.v3f;
};
}

If you wish to extract the JS type equivalent of a TypeGPU schema, you can do so with d.Infer:

type u32 =
import d
d
.
type Infer<T> = T extends {
readonly [$repr]: infer TRepr;
} ? TRepr : T
export Infer

Extracts the inferred representation of a resource. For inferring types as seen by the GPU, see

InferGPU

@example type A = Infer // => number type B = Infer<WgslArray> // => number[] type C = Infer<Atomic> // => number

Infer
<typeof
import d
d
.
const u32: d.U32
export u32

A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)

Can also be called to cast a value to an u32 in accordance with WGSL casting rules.

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

@example const value = u32(7); // 7

@example const value = u32(3.14); // 3

@example const value = u32(-1); // 4294967295

@example const value = u32(-3.1); // 0

u32
>;
type u32 = number
type Circle =
import d
d
.
type Infer<T> = T extends {
readonly [$repr]: infer TRepr;
} ? TRepr : T
export Infer

Extracts the inferred representation of a resource. For inferring types as seen by the GPU, see

InferGPU

@example type A = Infer // => number type B = Infer<WgslArray> // => number[] type C = Infer<Atomic> // => number

Infer
<typeof
const Circle: d.WgslStruct<{
centerPos: d.Vec3i;
radius: d.F32;
}>
Circle
>;
type Circle = {
centerPos: d.v3i;
radius: number;
}

Defined data structures automatically measure and hold information about their memory layout parameters.

import d
d
.
function sizeOf(schema: d.AnyData): number
export sizeOf

Returns the size (in bytes) of data represented by the schema.

sizeOf
(
const Circle: d.WgslStruct<{
centerPos: d.Vec3i;
radius: d.F32;
}>
Circle
) // 16
import d
d
.
function alignmentOf(schema: d.AnyData): number
export alignmentOf

Returns the alignment (in bytes) of data represented by the schema.

alignmentOf
(
const Circle: d.WgslStruct<{
centerPos: d.Vec3i;
radius: d.F32;
}>
Circle
) // 16

Struct schemas adjust the padding and alignment automatically, so that they comply with WebGPU’s memory alignment rules. It is also possible to override default byte alignment and size for particular fields via the d.align and d.size functions.

const
const Boid: d.WgslStruct<{
position: d.Decorated<d.Vec3u, [d.Align<32>]>;
velocity: d.Vec3f;
color: d.Vec4f;
isActive: d.Decorated<d.Bool, [d.Size<8>]>;
}>
Boid
=
import d
d
.
struct<{
position: d.Decorated<d.Vec3u, [d.Align<32>]>;
velocity: d.Vec3f;
color: d.Vec4f;
isActive: d.Decorated<d.Bool, [d.Size<8>]>;
}>(props: {
position: d.Decorated<d.Vec3u, [d.Align<32>]>;
velocity: d.Vec3f;
color: d.Vec4f;
isActive: d.Decorated<d.Bool, [d.Size<8>]>;
}): d.WgslStruct<...>
export struct

Creates a struct schema that can be used to construct GPU buffers. Ensures proper alignment and padding of properties (as opposed to a d.unstruct schema). The order of members matches the passed in properties object.

@example const CircleStruct = d.struct({ radius: d.f32, pos: d.vec3f });

@paramprops Record with string keys and TgpuData values, each entry describing one struct member.

struct
({
position: d.Decorated<d.Vec3u, [d.Align<32>]>
position
:
import d
d
.
align<32, d.Vec3u>(alignment: 32, data: d.Vec3u): d.Decorated<d.Vec3u, [d.Align<32>]>
export align

Gives the wrapped data-type a custom byte alignment. Useful in order to fulfill uniform alignment requirements.

@example const Data = d.struct({ a: u32, // takes up 4 bytes // 12 bytes of padding, because b is custom aligned to multiples of 16 bytes b: d.align(16, u32), });

@paramalignment The multiple of bytes this data should align itself to.

@paramdata The data-type to align.

align
(32,
import d
d
.
const vec3u: d.Vec3u
export vec3u

Schema representing vec3u - a vector with 3 elements of type u32. Also a constructor function for this vector value.

@example const vector = d.vec3u(); // (0, 0, 0) const vector = d.vec3u(1); // (1, 1, 1) const vector = d.vec3u(1, 2, 3); // (1, 2, 3)

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

vec3u
), // Aligned to multiples of 32 bytes
velocity: d.Vec3f
velocity
:
import d
d
.
const vec3f: d.Vec3f
export vec3f

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

@example const vector = d.vec3f(); // (0.0, 0.0, 0.0) const vector = d.vec3f(1); // (1.0, 1.0, 1.0) const vector = d.vec3f(1, 2, 3.5); // (1.0, 2.0, 3.5)

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

vec3f
,
color: d.Vec4f
color
:
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
,
isActive: d.Decorated<d.Bool, [d.Size<8>]>
isActive
:
import d
d
.
size<8, d.Bool>(size: 8, data: d.Bool): d.Decorated<d.Bool, [d.Size<8>]>
export size

Adds padding bytes after the wrapped data-type, until the whole value takes up size bytes.

@example const Data = d.struct({ a: d.size(16, u32), // takes up 16 bytes, instead of 4 b: u32, // starts at byte 16, because a has a custom size });

@paramsize The amount of bytes that should be reserved for this data-type.

@paramdata The data-type to wrap.

size
(8,
import d
d
.
const bool: d.Bool
export bool

A schema that represents a boolean value. (equivalent to bool in WGSL)

Can also be called to cast a value to a bool in accordance with WGSL casting rules.

@example const value = bool(); // false

@example const value = bool(0); // false

@example const value = bool(-0); // false

@example const value = bool(21.37); // true

bool
), // Has a minimum size of 8 bytes
});

To define arrays of known constant length, use the d.arrayOf function with the schema representing the element type and with the length of the array.

const
const MyArray: d.WgslArray<d.F32>
MyArray
=
import d
d
.
arrayOf<d.F32>(elementType: d.F32, elementCount: number): d.WgslArray<d.F32> (+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 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
, 4);
const myDefaultArray =
const MyArray: d.WgslArray
() => number[] (+1 overload)
MyArray
(); // [0, 0, 0, 0]
const myDefaultArray: number[]
const
const myInitializedArray: number[]
myInitializedArray
=
const MyArray: d.WgslArray
<d.F32>(elements: number[]) => number[] (+1 overload)
MyArray
([1, 0, 0.5, 20]);

You can also call d.arrayOf without specifying the array length. This returns a partially applied schema function, allowing you to provide the length later or use the schema to declare WGSL runtime-sized arrays.

const ArrayPartialSchema =
import d
d
.
arrayOf<d.F32>(elementType: d.F32, elementCount?: undefined): (elementCount: number) => d.WgslArray<d.F32> (+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 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 ArrayPartialSchema: (elementCount: number) => d.WgslArray<d.F32>
const array =
const ArrayPartialSchema: (elementCount: number) => d.WgslArray<d.F32>
ArrayPartialSchema
(2)([1.2, 19.29]);
const array: number[]

One of the biggest differences between JavaScript and WGSL is the existence of value/reference types. Let’s take a look at a simple TGSL function and the WGSL code it resolves to.

// TGSL
const
const MyStruct: d.WgslStruct<{
n: d.U32;
}>
MyStruct
=
import d
d
.
struct<{
n: d.U32;
}>(props: {
n: d.U32;
}): d.WgslStruct<{
n: d.U32;
}>
export struct

Creates a struct schema that can be used to construct GPU buffers. Ensures proper alignment and padding of properties (as opposed to a d.unstruct schema). The order of members matches the passed in properties object.

@example const CircleStruct = d.struct({ radius: d.f32, pos: d.vec3f });

@paramprops Record with string keys and TgpuData values, each entry describing one struct member.

struct
({
n: d.U32
n
:
import d
d
.
const u32: d.U32
export u32

A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)

Can also be called to cast a value to an u32 in accordance with WGSL casting rules.

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

@example const value = u32(7); // 7

@example const value = u32(3.14); // 3

@example const value = u32(-1); // 4294967295

@example const value = u32(-3.1); // 0

u32
});
const
const myFn: TgpuFn<() => d.Void>
myFn
=
const tgpu: {
fn: {
<Args extends d.AnyData[] | []>(argTypes: Args, returnType?: undefined): TgpuFnShell<Args, d.Void>;
<Args extends d.AnyData[] | [], Return extends d.AnyData>(argTypes: Args, returnType: Return): TgpuFnShell<Args, Return>;
};
... 7 more ...;
'~unstable': {
...;
};
}
tgpu
.
fn: <[]>(argTypes: [], returnType?: undefined) => TgpuFnShell<[], d.Void> (+1 overload)
fn
([])(() => {
const
const s1: {
n: number;
}
s1
=
const MyStruct: d.WgslStruct
(props: {
n: number;
}) => {
n: number;
} (+1 overload)
MyStruct
({
n: number
n
: 0 });
const
const s2: {
n: number;
}
s2
=
const s1: {
n: number;
}
s1
;
const s2: {
n: number;
}
s2
.
n: number
n
= 1; // s1 is modified
});
// WGSL
struct MyStruct {
n: u32,
}
fn myFn(){
var s1 = MyStruct(0);
var s2 = s1;
s2.n = 1; // s1 is not modified
}

On the JS side, s2 is a reference to s1 and therefore s1 is modified when s2 is modified. On the WGSL side, the assignment operator copies the value of s1, and thus s1 is not modified later on.

To help with this issue, schema calls can be used as “copy constructors”, that copy the value on the JS side, and disappear on the WGSL side:

// TGSL
const
const MyStruct: d.WgslStruct<{
n: d.U32;
}>
MyStruct
=
import d
d
.
struct<{
n: d.U32;
}>(props: {
n: d.U32;
}): d.WgslStruct<{
n: d.U32;
}>
export struct

Creates a struct schema that can be used to construct GPU buffers. Ensures proper alignment and padding of properties (as opposed to a d.unstruct schema). The order of members matches the passed in properties object.

@example const CircleStruct = d.struct({ radius: d.f32, pos: d.vec3f });

@paramprops Record with string keys and TgpuData values, each entry describing one struct member.

struct
({
n: d.U32
n
:
import d
d
.
const u32: d.U32
export u32

A schema that represents an unsigned 32-bit integer value. (equivalent to u32 in WGSL)

Can also be called to cast a value to an u32 in accordance with WGSL casting rules.

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

@example const value = u32(7); // 7

@example const value = u32(3.14); // 3

@example const value = u32(-1); // 4294967295

@example const value = u32(-3.1); // 0

u32
});
const
const myFn: TgpuFn<() => d.Void>
myFn
=
const tgpu: {
fn: {
<Args extends d.AnyData[] | []>(argTypes: Args, returnType?: undefined): TgpuFnShell<Args, d.Void>;
<Args extends d.AnyData[] | [], Return extends d.AnyData>(argTypes: Args, returnType: Return): TgpuFnShell<Args, Return>;
};
... 7 more ...;
'~unstable': {
...;
};
}
tgpu
.
fn: <[]>(argTypes: [], returnType?: undefined) => TgpuFnShell<[], d.Void> (+1 overload)
fn
([])(() => {
const
const s1: {
n: number;
}
s1
=
const MyStruct: d.WgslStruct
(props: {
n: number;
}) => {
n: number;
} (+1 overload)
MyStruct
({
n: number
n
: 0 });
const
const s2: {
n: number;
}
s2
=
const MyStruct: d.WgslStruct
(props: {
n: number;
}) => {
n: number;
} (+1 overload)
MyStruct
(
const s1: {
n: number;
}
s1
); // deep copy of s1
const s2: {
n: number;
}
s2
.
n: number
n
= 1; // s1 is not modified
});
// WGSL
struct MyStruct {
n: u32,
}
fn myFn(){
var s1 = MyStruct(0);
var s2 = s1; // copies s1 into s2
s2.n = 1; // s1 is not modified
}