Slots
Slots are a powerful dependency injection mechanism in TypeGPU that allows you to write shader logic without having to tightly couple to specific resources. Similarly to bind group layouts, you can think of slots as of typed “holes” in TypeGPU shaders, that can be filled in later on from the outside. The main differences between slots and bound resources include the following:
- Slots are filled in before the shader module compile time, instead of just before the shader execution starts.
- Slots can contain not only buffers, but also basically any JavaScript value, even TypeGPU functions.
Main use cases for slots include:
- Generics — instead of rewriting a function for each generic parameter, it suffices to fill a slot with a different value.
- Passing callbacks — high-level libraries based on TypeGPU can leave slots for user-defined functions to call.
Basic usage
Section titled “Basic usage”A slot is created using the tgpu.slot() function and can optionally take a default value:
const const filterColorSlot: TgpuSlot<d.v3f>
filterColorSlot = 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");}
tgpu.slot: <d.v3f>(defaultValue?: d.v3f | undefined) => TgpuSlot<d.v3f>
slot<import d
d.export v3f
Interface representing its WGSL vector type counterpart: vec3f or vec3.
A vector with 3 elements of type f32
v3f>(); // Slot for a 3D vector.const const mySlot: TgpuSlot<number>
mySlot = 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");}
tgpu.slot: <number>(defaultValue?: number | undefined) => TgpuSlot<number>
slot<number>(42); // Slot with a default value.
interface interface Config
Config { Config.fogEnabled: boolean
fogEnabled: boolean; Config.tint: d.v3f
tint: import d
d.export v3f
Interface representing its WGSL vector type counterpart: vec3f or vec3.
A vector with 3 elements of type f32
v3f;}
const const configSlot: TgpuSlot<Config>
configSlot = 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");}
tgpu.slot: <Config>(defaultValue?: Config | undefined) => TgpuSlot<Config>
slot<interface Config
Config>();You can access a slot’s value using .$:
const value = mySlot.$;Slots are resolved during the TypeGPU resolution phase. The slot object itself does not hold any value. Instead, you can bind it in one of two ways.
Binding after defining a function
Section titled “Binding after defining a function”The first way to bind a value to a slot is to call the with method on a wrapped TypeGPU function:
const const filterColorSlot: TgpuSlot<d.v3f>
filterColorSlot = 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");}
tgpu.slot: <d.v3f>(defaultValue?: d.v3f | undefined) => TgpuSlot<d.v3f>
slot<import d
d.export v3f
Interface representing its WGSL vector type counterpart: vec3f or vec3.
A vector with 3 elements of type f32
v3f>();
const const filter: (color: d.v3f) => d.v3f
filter = (color: d.v3f
color: import d
d.export v3f
Interface representing its WGSL vector type counterpart: vec3f or vec3.
A vector with 3 elements of type f32
v3f): import d
d.export v3f
Interface representing its WGSL vector type counterpart: vec3f or vec3.
A vector with 3 elements of type f32
v3f => { 'use gpu'; const const filterColor: d.v3f
filterColor = const filterColorSlot: TgpuSlot<d.v3f>
filterColorSlot.TgpuSlot<v3f>.$: d.v3f
$; return color: d.v3f
color.vecInfixNotation<v3f>.mul(other: number | d.v3f | d.m3x3f): d.v3f
mul(const filterColor: d.v3f
filterColor);};
// Bind the filter function with a red color.const const filterWithRed: TgpuGenericFn<(color: d.v3f) => d.v3f>
filterWithRed = 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");}
tgpu.fn: <(color: d.v3f) => d.v3f>(inner: (color: d.v3f) => d.v3f) => TgpuGenericFn<(color: d.v3f) => d.v3f> (+2 overloads)
fn(const filter: (color: d.v3f) => d.v3f
filter) .Withable<TgpuGenericFn<(color: d.v3f) => d.v3f>>.with<d.v3f>(slot: TgpuSlot<d.v3f>, value: Eventual<d.v3f>): TgpuGenericFn<(color: d.v3f) => d.v3f> (+2 overloads)
with(const filterColorSlot: TgpuSlot<d.v3f>
filterColorSlot, 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.
vec3f(1, 0, 0));
// Bind the filter function with a green color.const const filterWithGreen: TgpuGenericFn<(color: d.v3f) => d.v3f>
filterWithGreen = 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");}
tgpu.fn: <(color: d.v3f) => d.v3f>(inner: (color: d.v3f) => d.v3f) => TgpuGenericFn<(color: d.v3f) => d.v3f> (+2 overloads)
fn(const filter: (color: d.v3f) => d.v3f
filter) .Withable<TgpuGenericFn<(color: d.v3f) => d.v3f>>.with<d.v3f>(slot: TgpuSlot<d.v3f>, value: Eventual<d.v3f>): TgpuGenericFn<(color: d.v3f) => d.v3f> (+2 overloads)
with(const filterColorSlot: TgpuSlot<d.v3f>
filterColorSlot, 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.
vec3f(0, 1, 0));In the example above, after resolution we are left with two different WGSL functions:
fn filter_0(color: vec3f) -> vec3f{ var filterColor = vec3f(1, 0, 0); return (color * filterColor);}
fn filter_1(color: vec3f) -> vec3f{ var filterColor = vec3f(0, 1, 0); return (color * filterColor);}Binding during pipeline creation
Section titled “Binding during pipeline creation”The other way to fill in a slot is to call the with method during the creation of a TgpuComputePipeline or TgpuRenderPipeline:
const const resultBuffer: TgpuMutable<d.I32>
resultBuffer = const root: TgpuRoot
root.TgpuRoot.createMutable<d.I32>(typeSchema: d.I32, initial?: number | undefined): TgpuMutable<d.I32> (+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
.
createMutable(import d
d.const i32: d.I32export 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.
i32, 0);const const multiplierSlot: TgpuSlot<number>
multiplierSlot = 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");}
tgpu.slot: <number>(defaultValue?: number | undefined) => TgpuSlot<number>
slot<number>();
const const computeMultiply: TgpuComputeFn<{}>
computeMultiply = 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");}
tgpu.computeFn: (options: { workgroupSize: number[];}) => TgpuComputeFnShell<{}> (+1 overload)
computeFn({ workgroupSize: number[]
workgroupSize: [1] })(() => { const resultBuffer: TgpuMutable<d.I32>
resultBuffer.TgpuMutable<I32>.$: number
$ = const resultBuffer: TgpuMutable<d.I32>
resultBuffer.TgpuMutable<I32>.$: number
$ * const multiplierSlot: TgpuSlot<number>
multiplierSlot.TgpuSlot<number>.$: number
$;});
const const pipeline: TgpuComputePipeline
pipeline = const root: TgpuRoot
root .Withable<WithBinding>.with<number>(slot: TgpuSlot<number>, value: Eventual<number>): WithBinding (+2 overloads)
with(const multiplierSlot: TgpuSlot<number>
multiplierSlot, 3) .WithBinding.createComputePipeline<{}>(descriptor: TgpuComputePipeline.Descriptor<{}>): TgpuComputePipeline
createComputePipeline({ compute: TgpuComputeFn<{}>
compute: const computeMultiply: TgpuComputeFn<{}>
computeMultiply });The pipeline above resolves to the following WGSL:
@group(0) @binding(0) var<storage, read_write> resultBuffer_1: i32;
@compute @workgroup_size(1) fn computeMultiply_0(){ resultBuffer_1 = (resultBuffer_1 * 3);}Inversion of control
Section titled “Inversion of control”Slots allow libraries to expose customization points to their users. They enable internal behavior to be modified without sacrificing type safety or performance.
const const defaultGravity: TgpuFn<(pos: d.Vec2f) => d.Vec2f>
defaultGravity = 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");}
tgpu.fn: <[d.Vec2f], d.Vec2f>(argTypes: [d.Vec2f], returnType: d.Vec2f) => TgpuFnShell<[d.Vec2f], d.Vec2f> (+2 overloads)
fn([import d
d.const vec2f: d.Vec2fexport vec2f
Schema representing vec2f - a vector with 2 elements of type f32.
Also a constructor function for this vector value.
vec2f], import d
d.const vec2f: d.Vec2fexport vec2f
Schema representing vec2f - a vector with 2 elements of type f32.
Also a constructor function for this vector value.
vec2f)((pos: d.v2f
pos) => { return 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.
vec2f(0, -9.8);});
export const gravitySlot = 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");}
tgpu.slot: <TgpuFn<(pos: d.Vec2f) => d.Vec2f>>(defaultValue?: TgpuFn<(pos: d.Vec2f) => d.Vec2f> | undefined) => TgpuSlot<TgpuFn<(pos: d.Vec2f) => d.Vec2f>>
slot(const defaultGravity: TgpuFn<(pos: d.Vec2f) => d.Vec2f>
defaultGravity);const gravitySlot: TgpuSlot<TgpuFn<(pos: d.Vec2f) => d.Vec2f>>
export const const stepPhysics: TgpuFn<() => d.Void>
stepPhysics = 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");}
tgpu.fn: <[]>(argTypes: [], returnType?: undefined) => TgpuFnShell<[], d.Void> (+2 overloads)
fn([])(() => { for (const const obj: { position: d.v2f; velocity: d.v2f;}
obj of const objects: TgpuReadonly<d.WgslArray<d.WgslStruct<{ position: d.Vec2f; velocity: d.Vec2f;}>>>
objects.TgpuReadonly<WgslArray<WgslStruct<{ position: Vec2f; velocity: Vec2f; }>>>.$: { position: d.v2f; velocity: d.v2f;}[]
$) { // Calling whatever implementation was provided. const const gravity: d.v2f
gravity = const gravitySlot: TgpuSlot<TgpuFn<(pos: d.Vec2f) => d.Vec2f>>
gravitySlot.TgpuSlot<TgpuFn<(pos: Vec2f) => Vec2f>>.$: (pos: d.v2f) => d.v2f
$(const obj: { position: d.v2f; velocity: d.v2f;}
obj.position: d.v2f
position);
const obj: { position: d.v2f; velocity: d.v2f;}
obj.velocity: d.v2f
velocity = add<d.v2f>(lhs: d.v2f, rhs: d.v2f): d.v2f (+4 overloads)
add(const obj: { position: d.v2f; velocity: d.v2f;}
obj.velocity: d.v2f
velocity, mul<d.v2f>(lhs: d.v2f, rhs: number): d.v2f (+7 overloads)
mul(const gravity: d.v2f
gravity, const deltaTime: TgpuUniform<d.F32>
deltaTime.TgpuUniform<F32>.$: number
$)); }});import { stepPhysics, gravitySlot } from './physics.ts';
const gravityTowardsCenter = tgpu.fn([vec2f], vec2f)((pos) => { return mul(normalize(pos), -1);});
const stepPhysicsCustomized = stepPhysics .with(gravitySlot, gravityTowardsCenter);
const main = tgpu.computeFn()(() => { stepPhysicsCustomized(); // <- Will use altered gravity.});Slots in raw WGSL
Section titled “Slots in raw WGSL”It is possible to use slots even in TypeGPU functions that are implemented in WGSL:
const const colorSlot: TgpuSlot<d.v3f>
colorSlot = 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");}
tgpu.slot: <d.v3f>(defaultValue?: d.v3f | undefined) => TgpuSlot<d.v3f>
slot(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.
vec3f(1, 0, 0));
const const getColor: TgpuFn<() => d.Vec3f>
getColor = 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");}
tgpu.fn: <[], d.Vec3f>(argTypes: [], returnType: d.Vec3f) => TgpuFnShell<[], d.Vec3f> (+2 overloads)
fn([], import d
d.const vec3f: d.Vec3fexport vec3f
Schema representing vec3f - a vector with 3 elements of type f32.
Also a constructor function for this vector value.
vec3f)`() { return colorSlot;}`.TgpuFnBase<() => Vec3f>.$uses(dependencyMap: Record<string, unknown>): TgpuFn<() => d.Vec3f>
$uses({ colorSlot: TgpuSlot<d.v3f>
colorSlot });The code above resolves to the following WGSL:
fn getColor() -> vec3f { return vec3f(1, 0, 0);}