Skip to content

Utilities

When working on top of some existing shader code, sometimes you may know for certain that some variable will be already defined and should be accessible in the code. In such scenario you can use tgpu['~unstable'].rawCodeSnippet — an advanced API that creates a typed shader expression which can be injected into the final shader bundle upon use.

// `EXISTING_GLOBAL` is an identifier that we know will be in the
// final shader bundle, but we cannot
// refer to it in any other way.
const
const existingGlobal: TgpuRawCodeSnippet<d.F32>
existingGlobal
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
['~unstable']
.
rawCodeSnippet<d.F32>(expression: string, type: d.F32, origin?: RawCodeSnippetOrigin | undefined): TgpuRawCodeSnippet<d.F32>
export rawCodeSnippet

An advanced API that creates a typed shader expression which can be injected into the final shader bundle upon use.

@paramexpression The code snippet that will be injected in place of foo.$

@paramtype The type of the expression

@param

origin Where the value originates from.

-- Which origin to choose?

Usually 'runtime' (the default) is a safe bet, but if you're sure that the expression or computation is constant (either a reference to a constant, a numeric literal, or an operation on constants), then pass 'constant' as it might lead to better optimizations.

If what the expression is a direct reference to an existing value (e.g. a uniform, a storage binding, ...), then choose from 'uniform', 'mutable', 'readonly', 'workgroup', 'private' or 'handle' depending on the address space of the referred value.

@example

// An identifier that we know will be in the
// final shader bundle, but we cannot
// refer to it in any other way.
const existingGlobal = tgpu['~unstable']
.rawCodeSnippet('EXISTING_GLOBAL', d.f32, 'constant');
const foo = () => {
'use gpu';
return existingGlobal.$ * 2;
};
const wgsl = tgpu.resolve([foo]);
// fn foo() -> f32 {
// return EXISTING_GLOBAL * 2;
// }

rawCodeSnippet
('EXISTING_GLOBAL',
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
, 'constant');
const
const foo: TgpuFn<() => d.F32>
foo
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
fn: <[], d.F32>(argTypes: [], returnType: d.F32) => TgpuFnShell<[], d.F32> (+2 overloads)
fn
([],
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
)(() => {
'use gpu';
return
const existingGlobal: TgpuRawCodeSnippet<d.F32>
existingGlobal
.
TgpuRawCodeSnippet<F32>.$: number
$
* 22;
});
const
const wgsl: string
wgsl
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/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 foo: TgpuFn<() => d.F32>
foo
]);
// fn foo() -> f32 {
// return (EXISTING_GLOBAL * 22f);
// }

The optional third parameter origin lets TypeGPU transpiler know how to optimize the code snippet, as well as allows for some transpilation-time validity checks.

Usually 'runtime' (the default) is a safe bet, but if you’re sure that the expression or computation is constant (either a reference to a constant, a numeric literal, or an operation on constants), then pass 'constant' as it might lead to better optimizations.

If what the expression is a direct reference to an existing value (e.g. a uniform, a storage binding, …), then choose from 'uniform', 'mutable', 'readonly', 'workgroup', 'private' or 'handle' depending on the address space of the referred value.

tgpu.comptime(func) creates a version of func that instead of being transpiled to WGSL, will be called during the WGSL code generation. This can be used to precompute and inject a value into the final shader code.

const
const color: TgpuComptime<(int: number) => d.v3f>
color
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
comptime: <(int: number) => d.v3f>(func: (int: number) => d.v3f) => TgpuComptime<(int: number) => d.v3f>

Creates a version of func that can called safely in a TypeGPU function to precompute and inject a value into the final shader code.

Note how the function passed into comptime doesn't have to be marked with 'use gpu'. That's because the function doesn't execute on the GPU, it gets executed before the shader code gets sent to the GPU.

@example

const color = tgpu.comptime((int: number) => {
const r = (int >> 16) & 0xff;
const g = (int >> 8) & 0xff;
const b = int & 0xff;
return d.vec3f(r / 255, g / 255, b / 255);
});
const material = (diffuse: d.v3f): d.v3f => {
'use gpu';
const albedo = color(0xff00ff);
return albedo.mul(diffuse);
};

comptime
((
int: number
int
: number) => {
const
const r: number
r
= (
int: number
int
>> 16) & 0xff;
const
const g: number
g
= (
int: number
int
>> 8) & 0xff;
const
const b: number
b
=
int: number
int
& 0xff;
return
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
(
const r: number
r
/ 255,
const g: number
g
/ 255,
const b: number
b
/ 255);
});
const
const material: TgpuFn<(diffuse: d.Vec3f) => d.Vec3f>
material
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
fn: <[d.Vec3f], d.Vec3f>(argTypes: [d.Vec3f], returnType: d.Vec3f) => TgpuFnShell<[d.Vec3f], d.Vec3f> (+2 overloads)
fn
([
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
],
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
)((
diffuse: d.v3f
diffuse
) => {
'use gpu';
const
const albedo: d.v3f
albedo
=
const color: (int: number) => d.v3f
color
(0xff00ff);
return
const albedo: d.v3f
albedo
.
vecInfixNotation<v3f>.mul(other: number | d.v3f | d.m3x3f): d.v3f
mul
(
diffuse: d.v3f
diffuse
);
});
const
const shader: string
shader
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/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 material: TgpuFn<(diffuse: d.Vec3f) => d.Vec3f>
material
]);
// fn material(diffuse: vec3f) -> vec3f {
// var albedo = vec3f(1, 0, 1);
// return (albedo * diffuse);
// }

Note how the function passed into comptime doesn’t have to be marked with 'use gpu' and can use Math. That’s because the function doesn’t execute on the GPU, it gets executed before the shader code gets sent to the GPU.

If a condition is known at resolution time (comptime), then typegpu prunes the unvisited block. Comptime-known conditions include:

  • referenced js values and operations on such, like std.pow(userSelection, 2) < THRESHOLD (note that these values will be concretized during shader resolution, if userSelection may change over time, use buffers to provide it),
  • values provided via slots,
  • values returned by comptime functions.
const
const counterEnabledSlot: TgpuSlot<boolean>
counterEnabledSlot
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
slot: <boolean>(defaultValue?: boolean | undefined) => TgpuSlot<boolean>
slot
<boolean>(false);
const
const counter: TgpuMutable<d.U32>
counter
=
const root: TgpuRoot
root
.
TgpuRoot.createMutable<d.U32>(typeSchema: d.U32, initial?: number | undefined): TgpuMutable<d.U32> (+1 overload)

Allocates memory on the GPU, allows passing data between host and shader. Can be mutated in-place on the GPU. For a general-purpose buffer, use

TgpuRoot.createBuffer

.

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

@paraminitial The initial value of the buffer. (optional)

createMutable
(
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 myFunction: TgpuFn<() => d.Void>
myFunction
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
fn: <[]>(argTypes: [], returnType?: undefined) => TgpuFnShell<[], d.Void> (+2 overloads)
fn
([])(() => {
if (
const counterEnabledSlot: TgpuSlot<boolean>
counterEnabledSlot
.
TgpuSlot<boolean>.$: boolean
$
)
const counter: TgpuMutable<d.U32>
counter
.
TgpuMutable<U32>.$: number
$
++;
});
// fn myFunction() {
//
// }
const
const myFunctionWithCounter: TgpuFn<() => d.Void>
myFunctionWithCounter
=
const myFunction: TgpuFn<() => d.Void>
myFunction
.
Withable<TgpuFn<() => Void>>.with<boolean>(slot: TgpuSlot<boolean>, value: Eventual<boolean>): TgpuFn<() => d.Void> (+2 overloads)
with
(
const counterEnabledSlot: TgpuSlot<boolean>
counterEnabledSlot
, true);
// "@group(0) @binding(0) var<storage, read_write> counter: u32;
//
// fn myFunction() {
// {
// counter++;
// }
// }"

Branch pruning also works for ternary operators.

const
const myFunction: TgpuFn<() => d.Void>
myFunction
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
fn: <[]>(argTypes: [], returnType?: undefined) => TgpuFnShell<[], d.Void> (+2 overloads)
fn
([])(() => {
const counterEnabledSlot: TgpuSlot<boolean>
counterEnabledSlot
.
TgpuSlot<boolean>.$: boolean
$
?
const counter: TgpuMutable<d.U32>
counter
.
TgpuMutable<U32>.$: number
$
++ :
var undefined
undefined
;
});

When working on top of some existing shader code, sometimes you may know for certain that some variable will be already defined and should be accessible in the code. In such scenario you can use tgpu['~unstable'].rawCodeSnippet — an advanced API that creates a typed shader expression which can be injected into the final shader bundle upon use.

// `EXISTING_GLOBAL` is an identifier that we know will be in the
// final shader bundle, but we cannot
// refer to it in any other way.
const
const existingGlobal: TgpuRawCodeSnippet<d.F32>
existingGlobal
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
['~unstable']
.
rawCodeSnippet<d.F32>(expression: string, type: d.F32, origin?: RawCodeSnippetOrigin | undefined): TgpuRawCodeSnippet<d.F32>
export rawCodeSnippet

An advanced API that creates a typed shader expression which can be injected into the final shader bundle upon use.

@paramexpression The code snippet that will be injected in place of foo.$

@paramtype The type of the expression

@param

origin Where the value originates from.

-- Which origin to choose?

Usually 'runtime' (the default) is a safe bet, but if you're sure that the expression or computation is constant (either a reference to a constant, a numeric literal, or an operation on constants), then pass 'constant' as it might lead to better optimizations.

If what the expression is a direct reference to an existing value (e.g. a uniform, a storage binding, ...), then choose from 'uniform', 'mutable', 'readonly', 'workgroup', 'private' or 'handle' depending on the address space of the referred value.

@example

// An identifier that we know will be in the
// final shader bundle, but we cannot
// refer to it in any other way.
const existingGlobal = tgpu['~unstable']
.rawCodeSnippet('EXISTING_GLOBAL', d.f32, 'constant');
const foo = () => {
'use gpu';
return existingGlobal.$ * 2;
};
const wgsl = tgpu.resolve([foo]);
// fn foo() -> f32 {
// return EXISTING_GLOBAL * 2;
// }

rawCodeSnippet
('EXISTING_GLOBAL',
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
, 'constant');
const
const foo: TgpuFn<() => d.F32>
foo
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
fn: <[], d.F32>(argTypes: [], returnType: d.F32) => TgpuFnShell<[], d.F32> (+2 overloads)
fn
([],
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
)(() => {
'use gpu';
return
const existingGlobal: TgpuRawCodeSnippet<d.F32>
existingGlobal
.
TgpuRawCodeSnippet<F32>.$: number
$
* 22;
});
const
const wgsl: string
wgsl
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/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 foo: TgpuFn<() => d.F32>
foo
]);
// fn foo() -> f32 {
// return (EXISTING_GLOBAL * 22f);
// }

The optional third parameter origin lets TypeGPU transpiler know how to optimize the code snippet, as well as allows for some transpilation-time validity checks.

Usually 'runtime' (the default) is a safe bet, but if you’re sure that the expression or computation is constant (either a reference to a constant, a numeric literal, or an operation on constants), then pass 'constant' as it might lead to better optimizations.

If what the expression is a direct reference to an existing value (e.g. a uniform, a storage binding, …), then choose from 'uniform', 'mutable', 'readonly', 'workgroup', 'private' or 'handle' depending on the address space of the referred value.

Yes, you read that correctly, TypeGPU implements logging to the console on the GPU! Just call console.log like you would in plain JavaScript, and open the console to see the results.

const
const callCountMutable: TgpuMutable<d.U32>
callCountMutable
=
const root: TgpuRoot
root
.
TgpuRoot.createMutable<d.U32>(typeSchema: d.U32, initial?: number | undefined): TgpuMutable<d.U32> (+1 overload)

Allocates memory on the GPU, allows passing data between host and shader. Can be mutated in-place on the GPU. For a general-purpose buffer, use

TgpuRoot.createBuffer

.

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

@paraminitial The initial value of the buffer. (optional)

createMutable
(
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
, 0);
const
const compute: TgpuGuardedComputePipeline<[]>
compute
=
const root: TgpuRoot
root
.
WithBinding.createGuardedComputePipeline<[]>(callback: () => void): TgpuGuardedComputePipeline<[]>

Creates a compute pipeline that executes the given callback in an exact number of threads. This is different from withCompute(...).createPipeline() in that it does a bounds check on the thread id, where as regular pipelines do not and work in units of workgroups.

@paramcallback A function converted to WGSL and executed on the GPU. It can accept up to 3 parameters (x, y, z) which correspond to the global invocation ID of the executing thread.

@example

If no parameters are provided, the callback will be executed once, in a single thread.

const fooPipeline = root
.createGuardedComputePipeline(() => {
'use gpu';
console.log('Hello, GPU!');
});
fooPipeline.dispatchThreads();
// [GPU] Hello, GPU!

@example

One parameter means n-threads will be executed in parallel.

const fooPipeline = root
.createGuardedComputePipeline((x) => {
'use gpu';
if (x % 16 === 0) {
// Logging every 16th thread
console.log('I am the', x, 'thread');
}
});
// executing 512 threads
fooPipeline.dispatchThreads(512);
// [GPU] I am the 256 thread
// [GPU] I am the 272 thread
// ... (30 hidden logs)
// [GPU] I am the 16 thread
// [GPU] I am the 240 thread

createGuardedComputePipeline
(() => {
'use gpu';
const callCountMutable: TgpuMutable<d.U32>
callCountMutable
.
TgpuMutable<U32>.$: number
$
+= 1;
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
('Call number',
const callCountMutable: TgpuMutable<d.U32>
callCountMutable
.
TgpuMutable<U32>.$: number
$
);
});
const compute: TgpuGuardedComputePipeline<[]>
compute
.
TgpuGuardedComputePipeline<[]>.dispatchThreads(): void

Dispatches the pipeline. Unlike TgpuComputePipeline.dispatchWorkgroups(), this method takes in the number of threads to run in each dimension.

Under the hood, the number of expected threads is sent as a uniform, and "guarded" by a bounds check.

dispatchThreads
();
const compute: TgpuGuardedComputePipeline<[]>
compute
.
TgpuGuardedComputePipeline<[]>.dispatchThreads(): void

Dispatches the pipeline. Unlike TgpuComputePipeline.dispatchWorkgroups(), this method takes in the number of threads to run in each dimension.

Under the hood, the number of expected threads is sent as a uniform, and "guarded" by a bounds check.

dispatchThreads
();
// Eventually...
// "[GPU] Call number 1"
// "[GPU] Call number 2"

Currently supported data types for logging include scalars, vectors, matrices, structs, and fixed-size arrays.

Under the hood, TypeGPU translates console.log to a series of serializing functions that write the logged arguments to a buffer that is read and deserialized after every draw/dispatch call.

The buffer is of fixed size, which may limit the total amount of information that can be logged; if the buffer overflows, additional logs are dropped. If that’s an issue, you may specify the size manually when creating the root object.

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

@moduletypegpu

tgpu
.
init: (options?: InitOptions) => Promise<TgpuRoot>

Requests a new GPU device and creates a root around it. If a specific device should be used instead, use

@seeinitFromDevice. *

@example

When given no options, the function will ask the browser for a suitable GPU device.

const root = await tgpu.init();

@example

If there are specific options that should be used when requesting a device, you can pass those in.

const adapterOptions: GPURequestAdapterOptions = ...;
const deviceDescriptor: GPUDeviceDescriptor = ...;
const root = await tgpu.init({ adapter: adapterOptions, device: deviceDescriptor });

init
({
unstable_logOptions?: LogGeneratorOptions
unstable_logOptions
: {
LogGeneratorOptions.logCountLimit?: number

The maximum number of logs that appear during a single draw/dispatch call. If this number is exceeded, a warning containing the total number of calls is logged and further logs are dropped.

@default64

logCountLimit
: 32,
LogGeneratorOptions.logSizeLimit?: number

The total number of bytes reserved for each log call. If this number is exceeded, an exception is thrown during resolution.

@default252

logSizeLimit
: 8, // in bytes, enough to fit 2*u32
},
});
/* vertex shader */
const
const mainFragment: TgpuFragmentFn<{}, d.Vec4f>
mainFragment
=
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
fragmentFn: <{
pos: d.BuiltinPosition;
}, d.Vec4f>(options: {
in: {
pos: d.BuiltinPosition;
};
out: d.Vec4f;
}) => TgpuFragmentFnShell<{
pos: d.BuiltinPosition;
}, d.Vec4f> (+1 overload)
fragmentFn
({
in: {
pos: d.BuiltinPosition;
}
in
: {
pos: d.BuiltinPosition
pos
:
import d
d
.
const builtin: {
readonly vertexIndex: d.BuiltinVertexIndex;
readonly instanceIndex: d.BuiltinInstanceIndex;
readonly clipDistances: d.BuiltinClipDistances;
readonly position: d.BuiltinPosition;
readonly frontFacing: d.BuiltinFrontFacing;
readonly fragDepth: d.BuiltinFragDepth;
readonly primitiveIndex: BuiltinPrimitiveIndex;
readonly sampleIndex: d.BuiltinSampleIndex;
readonly sampleMask: d.BuiltinSampleMask;
readonly localInvocationId: d.BuiltinLocalInvocationId;
readonly localInvocationIndex: d.BuiltinLocalInvocationIndex;
... 6 more ...;
readonly numSubgroups: BuiltinNumSubgroups;
}
export builtin
builtin
.
position: d.BuiltinPosition
position
},
out: d.Vec4f
out
:
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
,
})(({
pos: d.v4f
pos
}) => {
// this log fits in 8 bytes
// static strings do not count towards the serialized log size
var console: Console

The console module provides a simple debugging console that is similar to the JavaScript console mechanism provided by web browsers.

The module exports two specific components:

  • A Console class with methods such as console.log(), console.error() and console.warn() that can be used to write to any Node.js stream.
  • A global console instance configured to write to process.stdout and process.stderr. The global console can be used without importing the node:console module.

Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.

Example using the global console:

console.log('hello world');
// Prints: hello world, to stdout
console.log('hello %s', 'world');
// Prints: hello world, to stdout
console.error(new Error('Whoops, something bad happened'));
// Prints error message and stack trace to stderr:
// Error: Whoops, something bad happened
// at [eval]:5:15
// at Script.runInThisContext (node:vm:132:18)
// at Object.runInThisContext (node:vm:309:38)
// at node:internal/process/execution:77:19
// at [eval]-wrapper:6:22
// at evalScript (node:internal/process/execution:76:60)
// at node:internal/main/eval_string:23:3
const name = 'Will Robinson';
console.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to stderr

Example using the Console class:

const out = getStreamSomehow();
const err = getStreamSomehow();
const myConsole = new console.Console(out, err);
myConsole.log('hello world');
// Prints: hello world, to out
myConsole.log('hello %s', 'world');
// Prints: hello world, to out
myConsole.error(new Error('Whoops, something bad happened'));
// Prints: [Error: Whoops, something bad happened], to err
const name = 'Will Robinson';
myConsole.warn(`Danger ${name}! Danger!`);
// Prints: Danger Will Robinson! Danger!, to err

@seesource

console
.
Console.log(message?: any, ...optionalParams: any[]): void (+1 overload)

Prints to stdout with newline. Multiple arguments can be passed, with the first used as the primary message and all additional used as substitution values similar to printf(3) (the arguments are all passed to util.format()).

const count = 5;
console.log('count: %d', count);
// Prints: count: 5, to stdout
console.log('count:', count);
// Prints: count: 5, to stdout

See util.format() for more information.

@sincev0.1.100

log
('X:',
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
(
pos: d.v4f
pos
.
v4f.x: number
x
), 'Y:',
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
(
pos: d.v4f
pos
.
v4f.y: number
y
));
return
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
(0, 1, 1, 1);
});
/* pipeline creation and draw call */

Other supported console functionalities include console.debug, console.info, console.warn, console.error and console.clear.

There are some limitations (some of which we intend to alleviate in the future):

  • console.log only works when used in TypeGPU functions that are transitively called in a TypeGPU pipeline. Otherwise, for example when using tgpu.resolve on a WGSL template, logs are ignored.
  • console.log only works in fragment and compute shaders. This is due to a WebGPU limitation that does not allow modifying buffers during the vertex shader stage.
  • console.log currently does not support template literals (but you can use string substitutions, or just pass multiple arguments instead).

TypeGPU supports for...of... loops in shader functions. The only constraints are that the loop variable must be declared with const and the iterable must be stored in a variable.

const
const processNeighbors: (cell: d.v2i) => void
processNeighbors
= (
cell: d.v2i
cell
:
import d
d
.
export v2i

Interface representing its WGSL vector type counterpart: vec2i or vec2. A vector with 2 elements of type i32

v2i
) => {
'use gpu';
const
const offsets: d.v2i[]
offsets
= [
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
(0, 1),
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
(0, -1),
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
(1, 0),
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
(-1, 0),
];
for (const
const offset: d.v2i
offset
of
const offsets: d.v2i[]
offsets
) {
const processNeighbor: (cell: d.v2i) => void
processNeighbor
(
cell: d.v2i
cell
.
vecInfixNotation<v2i>.add(other: number | d.v2i): d.v2i
add
(
const offset: d.v2i
offset
));
}
};

For code with small, fixed iteration counts, you can use tgpu.unroll to unroll loops at compile time. This eliminates branch prediction overhead and can significantly improve performance.

Wrap your iterable with tgpu.unroll():

const
const processNeighbors: (cell: d.v2i) => void
processNeighbors
= (
cell: d.v2i
cell
:
import d
d
.
export v2i

Interface representing its WGSL vector type counterpart: vec2i or vec2. A vector with 2 elements of type i32

v2i
) => {
'use gpu';
for (const
const dy: number
dy
of
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
unroll: <number[]>(value: number[]) => number[]
unroll
([-1, 0, 1])) {
for (const
const dx: number
dx
of
const tgpu: {
const: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/constant/tgpuConstant").constant;
fn: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/tgpuFn").fn;
comptime: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/function/comptime").comptime;
resolve: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolve;
resolveWithContext: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/resolve/tgpuResolve").resolveWithContext;
init: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").init;
initFromDevice: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/root/init").initFromDevice;
slot: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/slot").slot;
lazy: typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/core/slot/lazy").lazy;
... 10 more ...;
'~unstable': typeof import("/home/runner/work/TypeGPU/TypeGPU/packages/typegpu/src/tgpuUnstable");
}

@moduletypegpu

tgpu
.
unroll: <number[]>(value: number[]) => number[]
unroll
([-1, 0, 1])) {
const processNeighbor: (cell: d.v2i) => void
processNeighbor
(
cell: d.v2i
cell
.
vecInfixNotation<v2i>.add(other: number | d.v2i): d.v2i
add
(
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
(
const dx: number
dx
,
const dy: number
dy
)));
}
}
};