Skip to content

@typegpu/noise

The @typegpu/noise package offers a set of pseudo-random utilities for use in TypeGPU and WebGPU projects. At its core, the package provides a pseudo-random number generator for uniformly distributed values (same probability for all numbers) in the range [0, 1), as well as higher-level utilities built on top.

It also features a Perlin noise implementation, which is useful for generating smooth, natural-looking variations in visual effects, terrains, and other procedural elements.

Each utility function described in this guide is usable from the context of both TypeGPU and vanilla WebGPU. This makes it really simple to leverage the TypeGPU ecosystem in your WebGPU projects, without needing to migrate large parts of your codebase.

Calling utility functions from TypeGPU functions links them automatically. In the example below, resolving randomVec2f into a shader will include the code for randf.sample and all of its dependencies.

import {
const randf: {
seed: typeof randSeed;
seed2: typeof randSeed2;
seed3: typeof randSeed3;
seed4: typeof randSeed4;
sample: typeof randFloat01;
sampleExclusive: typeof randUniformExclusive;
normal: typeof randNormal;
exponential: typeof randExponential;
cauchy: typeof randCauchy;
bernoulli: typeof randBernoulli;
... 7 more ...;
onUnitSphere: typeof randOnUnitSphere;
}
randf
} from '@typegpu/noise';
const
const randomVec2f: TgpuFn<() => d.Vec2f>
randomVec2f
=
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.Vec2f>(argTypes: [], returnType: d.Vec2f) => TgpuFnShell<[], d.Vec2f> (+2 overloads)
fn
([],
import d
d
.
const vec2f: d.Vec2f
export vec2f

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

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

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

vec2f
)(() => {
const
const x: number
x
=
const randf: {
seed: typeof randSeed;
seed2: typeof randSeed2;
seed3: typeof randSeed3;
seed4: typeof randSeed4;
sample: typeof randFloat01;
sampleExclusive: typeof randUniformExclusive;
normal: typeof randNormal;
exponential: typeof randExponential;
cauchy: typeof randCauchy;
bernoulli: typeof randBernoulli;
... 7 more ...;
onUnitSphere: typeof randOnUnitSphere;
}
randf
.
sample: () => number

Returns a random f32 value in [0, 1) range.

sample
(); // returns a random float in [0, 1)
const
const y: number
y
=
const randf: {
seed: typeof randSeed;
seed2: typeof randSeed2;
seed3: typeof randSeed3;
seed4: typeof randSeed4;
sample: typeof randFloat01;
sampleExclusive: typeof randUniformExclusive;
normal: typeof randNormal;
exponential: typeof randExponential;
cauchy: typeof randCauchy;
bernoulli: typeof randBernoulli;
... 7 more ...;
onUnitSphere: typeof randOnUnitSphere;
}
randf
.
sample: () => number

Returns a random f32 value in [0, 1) range.

sample
(); // returns the next random float in [0, 1)
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.

@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
(
const x: number
x
,
const y: number
y
);
});
// ...

The tgpu.resolve API can be used to inject TypeGPU resources (constants, functions, etc.) into a WGSL shader.

In the example below, the sample function is accessed both as a named function, and as part of the randf object. The resolution mechanism handles deduplication out of the box, as well as omits code that is unused by your shader, so only one definition of sample will be included in the final shader.

import {
const randf: {
seed: typeof randSeed;
seed2: typeof randSeed2;
seed3: typeof randSeed3;
seed4: typeof randSeed4;
sample: typeof randFloat01;
sampleExclusive: typeof randUniformExclusive;
normal: typeof randNormal;
exponential: typeof randExponential;
cauchy: typeof randCauchy;
bernoulli: typeof randBernoulli;
... 7 more ...;
onUnitSphere: typeof randOnUnitSphere;
}
randf
} from '@typegpu/noise';
// `typegpu` is necessary to inject library code into your custom shader
import
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
from 'typegpu';
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: (options: TgpuExtendedResolveOptions) => 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
({
TgpuExtendedResolveOptions.template?: string | undefined

The code template to use for the resolution. All external names will be replaced with their resolved values.

@default''

template
: `
fn random_vec2f() -> vec2f {
// Accessing the 'sample' function directly
let x = sample();
// Accessing the 'sample' function as part of the 'randf' object
let y = randf.sample();
return vec2f(x, y);
}
// ...
`,
TgpuExtendedResolveOptions.externals: Record<string, object | Wgsl>

Map of external names to their resolvable values.

externals
: {
sample: TgpuFn<() => d.F32>
sample
:
const randf: {
seed: typeof randSeed;
seed2: typeof randSeed2;
seed3: typeof randSeed3;
seed4: typeof randSeed4;
sample: typeof randFloat01;
sampleExclusive: typeof randUniformExclusive;
normal: typeof randNormal;
exponential: typeof randExponential;
cauchy: typeof randCauchy;
bernoulli: typeof randBernoulli;
... 7 more ...;
onUnitSphere: typeof randOnUnitSphere;
}
randf
.
sample: TgpuFn<() => d.F32>

Returns a random f32 value in [0, 1) range.

sample
,
randf: {
seed: typeof randSeed;
seed2: typeof randSeed2;
seed3: typeof randSeed3;
seed4: typeof randSeed4;
sample: typeof randFloat01;
sampleExclusive: typeof randUniformExclusive;
normal: typeof randNormal;
exponential: typeof randExponential;
cauchy: typeof randCauchy;
bernoulli: typeof randBernoulli;
... 7 more ...;
onUnitSphere: typeof randOnUnitSphere;
}
randf
},
});
// The shader is just a WGSL string
shader;
const shader: string

Does this mean we allow object access inside of WGSL shaders?… yes, yes we do 🙈. To learn more about resolution, check our “Resolve” guide

The @typegpu/noise package provides a pseudo-random number generator (PRNG) that generates uniformly distributed random numbers in the range [0, 1). Each call to randf.sample returns the next random float in the sequence, allowing for predictable and repeatable results. The seed can be set or reset using a set of randf.seedN functions, where N is the number of components our seed has.

import
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
, {
import d
d
} from 'typegpu';
import {
const randf: {
seed: typeof randSeed;
seed2: typeof randSeed2;
seed3: typeof randSeed3;
seed4: typeof randSeed4;
sample: typeof randFloat01;
sampleExclusive: typeof randUniformExclusive;
normal: typeof randNormal;
exponential: typeof randExponential;
cauchy: typeof randCauchy;
bernoulli: typeof randBernoulli;
... 7 more ...;
onUnitSphere: typeof randOnUnitSphere;
}
randf
} from '@typegpu/noise';
const
const main: TgpuFragmentFn<{}, d.Vec4f>
main
=
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
}) => {
const randf: {
seed: typeof randSeed;
seed2: typeof randSeed2;
seed3: typeof randSeed3;
seed4: typeof randSeed4;
sample: typeof randFloat01;
sampleExclusive: typeof randUniformExclusive;
normal: typeof randNormal;
exponential: typeof randExponential;
cauchy: typeof randCauchy;
bernoulli: typeof randBernoulli;
... 7 more ...;
onUnitSphere: typeof randOnUnitSphere;
}
randf
.
seed2: (seed: d.v2f) => void

Threads do not share the generator's State. As a result, unless you change the seed in each thread, each thread will produce the same sequence. randf.randSeed2 sets the private seed of the thread.

@paramseed seed value to set. For the best results, all elements should be in [-1000, 1000] range.

seed2
(
pos: d.v4f
pos
.
xy: d.v2f
xy
); // Generate a different sequence for each pixel
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
(
const randf: {
seed: typeof randSeed;
seed2: typeof randSeed2;
seed3: typeof randSeed3;
seed4: typeof randSeed4;
sample: typeof randFloat01;
sampleExclusive: typeof randUniformExclusive;
normal: typeof randNormal;
exponential: typeof randExponential;
cauchy: typeof randCauchy;
bernoulli: typeof randBernoulli;
... 7 more ...;
onUnitSphere: typeof randOnUnitSphere;
}
randf
.
sample: () => number

Returns a random f32 value in [0, 1) range.

sample
(), // returns a random float in [0, 1)
const randf: {
seed: typeof randSeed;
seed2: typeof randSeed2;
seed3: typeof randSeed3;
seed4: typeof randSeed4;
sample: typeof randFloat01;
sampleExclusive: typeof randUniformExclusive;
normal: typeof randNormal;
exponential: typeof randExponential;
cauchy: typeof randCauchy;
bernoulli: typeof randBernoulli;
... 7 more ...;
onUnitSphere: typeof randOnUnitSphere;
}
randf
.
sample: () => number

Returns a random f32 value in [0, 1) range.

sample
(), // returns the next random float in [0, 1)
0.0,
1.0
);
});

There are higher-level utilities built on top of randf.sample. Most of the distributions can be derived from the fact that cumulative distribution functions (CDFs) are uniformly distributed on[0, 1] and can be easily inverted to generate random variables. We provide insights for probability enthusiasts. Let’s assume :

  • bernoulli - returns 1 with probability p, and 0 otherwise. You can think of it as the flip of a biased coin. p must be in the range [0, 1]
  • sampleExclusive - works the same as sample, but returns a value strictly between 0 and 1
  • exponential - returns a number based on the exponential distribution with a given rate. The rate must be greater than 0. It is commonly used for modeling the time until an event occurs
  • normal - returns a number based on the normal (Gaussian) distribution with a given mean (mu) and standard deviation (sigma). sigma must be > 0. Following transformation is called Box-Muller transform
  • cauchy - returns a number based on the Cauchy distribution with a given origin point (x0, gamma). gamma must be > 0. It can be interpreted as the probability distribution of the x-intercept of a light ray from the origin.
  • inUnitCircle - returns a random 2D vector uniformly distributed inside a unit circle
  • onUnitCircle - returns a random 2D vector uniformly distributed on the perimeter of a unit circle
  • inUnitCube - returns a random 3D vector uniformly distributed inside a unit cube
  • onUnitCube - returns a random 3D vector uniformly distributed on the surface of a unit cube
  • inHemisphere - returns a random 3D vector uniformly distributed inside an upper hemisphere oriented according to a given normal vector
  • onHemisphere - returns a random 3D vector uniformly distributed on the surface of an upper hemisphere oriented according to a given normal vector
  • inUnitSphere - returns a random 3D vector uniformly distributed inside a unit sphere. Thanks to the nature of the normal distribution, we can derive this distribution by sampling three coordinates from the and normalizing the result (this gives us a direction vector). Finally, we choose the radius as
  • onUnitSphere - returns a random 3D vector uniformly distributed on the surface of a unit sphere

The package exports an implementation for both 2D and 3D Perlin noise, perlin2d and perlin3d, respectively. Using it is as simple as calling the .sample function with the desired coordinates, and it returns a value in the range [-1, 1].

import {
import perlin2d
perlin2d
} from '@typegpu/noise';
const
const main: TgpuFragmentFn<{}, d.Vec4f>
main
=
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
}) => {
const
const noise: number
noise
=
import perlin2d
perlin2d
.
function sample(pos: d.v2f): number
export sample

Returns value of Perlin Noise at point pos

sample
(
pos: d.v4f
pos
.
xy: d.v2f
xy
.
vecInfixNotation<v2f>.mul(other: number | d.v2f | d.m2x2f): d.v2f
mul
(0.1)); // Scale the coordinates for smoother noise
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
(
const noise: number
noise
,
const noise: number
noise
,
const noise: number
noise
, 1); // Use the noise value for RGB channels
});

This simple usage is enough for most cases, but by default, perlin.sample computes the underlying gradients on-demand, per pixel. This can be inefficient for large images or when the same noise is sampled multiple times. To improve performance, you can precompute the gradients using either a Static or a Dynamic cache. In our tests, the efficiency gain can be up to 10x!

A static cache presumes that the domain of the noise function is fixed, and cannot change between shader invocations.

const
const cache: perlin3d.StaticPerlin3DCache
cache
=
import perlin3d
perlin3d
.
function staticCache(options: {
root: TgpuRoot;
size: d.v3u;
}): perlin3d.StaticPerlin3DCache
export staticCache

A statically-sized cache for perlin noise generation, which reduces the amount of redundant calculations if sampling is done more than once. If you'd like to change the size of the cache at runtime, see perlin3d.dynamicCacheConfig.

--- Basic usage

@example

const mainFragment = tgpu.fragmentFn({ out: d.vec4f })(() => {
const n = perlin3d.sample(d.vec3f(1.1, 2.2, 3.3));
// ...
});
const cache = perlin3d.staticCache({ root, size: d.vec3u(10, 10, 1) });
const pipeline = root
// Plugging the cache into the pipeline
.pipe(cache.inject())
// ...
.createRenderPipeline({
// ...
});

--- Wrapped coordinates

If the noise generator samples outside of the bounds of this cache, the space is wrapped around.

@example

const cache = perlin3d.staticCache({ root, size: d.vec3u(10, 10, 1) });
// ...
const value = perlin3d.sample(d.vec3f(0.5, 0, 0));
const wrappedValue = perlin3d.sample(d.vec3f(10.5, 0, 0)); // the same as `value`!

staticCache
({
root: TgpuRoot

The root to use for allocating resources.

root
,
size: d.v3u

The size of the cache.

size
:
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
(10, 10, 1) });
const
const pipeline: TgpuComputePipeline
pipeline
=
const root: TgpuRoot
root
// Plugging the cache into the pipeline
.
WithBinding.pipe(transform: (cfg: Configurable) => Configurable): WithBinding
pipe
(
const cache: perlin3d.StaticPerlin3DCache
cache
.
StaticPerlin3DCache.inject(): (cfg: Configurable) => Configurable
inject
())
// ...
.
WithBinding.createComputePipeline<{}>(descriptor: TgpuComputePipeline.Descriptor<{}>): TgpuComputePipeline
createComputePipeline
({
compute: TgpuComputeFn<{}>
compute
:
const main: TgpuComputeFn<{}>
main
});

Or in WebGPU:

const
const root: TgpuRoot
root
=
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
.
initFromDevice: (options: InitFromDeviceOptions) => TgpuRoot

Creates a root from the given device, instead of requesting it like

@seeinit. *

@example

const device: GPUDevice = ...;
const root = tgpu.initFromDevice({ device });

initFromDevice
({
device: GPUDevice
device
});
const
const cache: perlin3d.StaticPerlin3DCache
cache
=
import perlin3d
perlin3d
.
function staticCache(options: {
root: TgpuRoot;
size: d.v3u;
}): perlin3d.StaticPerlin3DCache
export staticCache

A statically-sized cache for perlin noise generation, which reduces the amount of redundant calculations if sampling is done more than once. If you'd like to change the size of the cache at runtime, see perlin3d.dynamicCacheConfig.

--- Basic usage

@example

const mainFragment = tgpu.fragmentFn({ out: d.vec4f })(() => {
const n = perlin3d.sample(d.vec3f(1.1, 2.2, 3.3));
// ...
});
const cache = perlin3d.staticCache({ root, size: d.vec3u(10, 10, 1) });
const pipeline = root
// Plugging the cache into the pipeline
.pipe(cache.inject())
// ...
.createRenderPipeline({
// ...
});

--- Wrapped coordinates

If the noise generator samples outside of the bounds of this cache, the space is wrapped around.

@example

const cache = perlin3d.staticCache({ root, size: d.vec3u(10, 10, 1) });
// ...
const value = perlin3d.sample(d.vec3f(0.5, 0, 0));
const wrappedValue = perlin3d.sample(d.vec3f(10.5, 0, 0)); // the same as `value`!

staticCache
({
root: TgpuRoot

The root to use for allocating resources.

root
,
size: d.v3u

The size of the cache.

size
:
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
(10, 10, 1) });
const {
const code: string
code
,
const usedBindGroupLayouts: TgpuBindGroupLayout<Record<string, TgpuLayoutEntry | null>>[]
usedBindGroupLayouts
,
const catchall: [number, TgpuBindGroup] | undefined
catchall
} =
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
.
resolveWithContext: (options: TgpuExtendedResolveOptions) => ResolutionResult (+1 overload)

Resolves a template with external values. Each external that is used will get resolved to a code string and replaced in the template. Any dependencies of the externals will also be resolved and included in the output.

@paramoptions - The options for the resolution.

@returns

@example

const Gradient = d.struct({ from: d.vec3f, to: d.vec3f });
const { code, usedBindGroupLayouts, catchall } = tgpu.resolveWithContext({
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);
// }

resolveWithContext
({
TgpuExtendedResolveOptions.template?: string | undefined

The code template to use for the resolution. All external names will be replaced with their resolved values.

@default''

template
: `
fn main() {
let value = perlin3d.sample(vec3f(0.5, 0., 0.));
let wrappedValue = perlin3d.sample(vec3f(10.5, 0., 0.)); // the same as 'value'!
// ...
}
// ...
`,
TgpuExtendedResolveOptions.externals: Record<string, object | Wgsl>

Map of external names to their resolvable values.

externals
: {
perlin3d: typeof perlin3d
perlin3d
},
TgpuResolveOptions.config?: ((cfg: Configurable) => Configurable) | undefined

A function to configure the resolution context.

config
: (
cfg: Configurable
cfg
) =>
cfg: Configurable
cfg
.
Configurable.pipe(transform: (cfg: Configurable) => Configurable): Configurable
pipe
(
const cache: perlin3d.StaticPerlin3DCache
cache
.
StaticPerlin3DCache.inject(): (cfg: Configurable) => Configurable
inject
())
// Or just:
// config: cache.inject()
});

If you need to change the size of the noise domain at runtime (in between shader invocations) without having to recompile the shader, you have to use a dynamic cache. With it comes a more complex setup.

const
const cacheConfig: perlin3d.DynamicPerlin3DCacheConfig<"perlin3dCache__">
cacheConfig
=
import perlin3d
perlin3d
.
function dynamicCacheConfig(options?: {
prefix?: undefined;
}): perlin3d.DynamicPerlin3DCacheConfig<"perlin3dCache__"> (+1 overload)
export dynamicCacheConfig

Used to instantiate caches for perlin noise generation, which reduce the amount of redundant calculations if sampling is done more than once. Their domain can be changed at runtime, which makes this cache dynamic (as opposed to perlin3d.staticCache, which is simpler at the cost of rigidity).

@param

options A set of general options for instances of this cache configuration.

--- Basic usage

@example

const perlinCacheConfig = perlin3d.dynamicCacheConfig();
// Contains all resources that the perlin cache needs access to
const dynamicLayout = tgpu.bindGroupLayout({ ...perlinCacheConfig.layout });
// ...
const root = await tgpu.init();
// Instantiating the cache with an initial size.
const perlinCache = perlinCacheConfig.instance(root, d.vec3u(10, 10, 1));
const pipeline = root
// Plugging the cache into the pipeline
.pipe(perlinCacheConfig.inject(dynamicLayout.$))
// ...
.createRenderPipeline({
// ...
});
const frame = () => {
// A bind group to fulfill the resource needs of the cache
const group = root.createBindGroup(dynamicLayout, { ...perlinCache.bindings });
pipeline
.with(group)
// ...
.draw(3);
};

dynamicCacheConfig
();
// Holds all resources the perlin cache needs access to
const
const dynamicLayout: TgpuBindGroupLayout<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>
dynamicLayout
=
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
.
bindGroupLayout: <{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>(entries: {
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}) => TgpuBindGroupLayout<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}> (+1 overload)
bindGroupLayout
({ ...
const cacheConfig: perlin3d.DynamicPerlin3DCacheConfig<"perlin3dCache__">
cacheConfig
.
DynamicPerlin3DCacheConfig<"perlin3dCache__">.layout: {
readonly perlin3dCache__size: {
uniform: d.Vec4u;
};
readonly perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}
layout
});
const
const pipeline: TgpuComputePipeline
pipeline
=
const root: TgpuRoot
root
// Plugging the cache into the pipeline
.
WithBinding.pipe(transform: (cfg: Configurable) => Configurable): WithBinding
pipe
(
const cacheConfig: perlin3d.DynamicPerlin3DCacheConfig<"perlin3dCache__">
cacheConfig
.
DynamicPerlin3DCacheConfig<"perlin3dCache__">.inject(layoutValue: {
readonly perlin3dCache__size: DataAccessorIn<d.Vec4u>;
readonly perlin3dCache__memory: DataAccessorIn<d.WgslArray<d.Vec3f>>;
}): (cfg: Configurable) => Configurable
inject
(
const dynamicLayout: TgpuBindGroupLayout<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>
dynamicLayout
.
TgpuBindGroupLayout<{ perlin3dCache__size: { uniform: d.Vec4u; }; perlin3dCache__memory: { storage: (elementCount: number) => WgslArray<Vec3f>; access: "readonly"; }; }>.$: {
perlin3dCache__size: d.v4u;
perlin3dCache__memory: d.v3f[];
}
$
))
// ...
.
WithBinding.createComputePipeline<{}>(descriptor: TgpuComputePipeline.Descriptor<{}>): TgpuComputePipeline
createComputePipeline
({
compute: TgpuComputeFn<{}>
compute
:
const main: TgpuComputeFn<{}>
main
});
// Instantiating the cache with an initial size.
const
const cache: perlin3d.DynamicPerlin3DCache<"perlin3dCache__">
cache
=
const cacheConfig: perlin3d.DynamicPerlin3DCacheConfig<"perlin3dCache__">
cacheConfig
.
DynamicPerlin3DCacheConfig<"perlin3dCache__">.instance(root: TgpuRoot, initialSize: d.v3u): perlin3d.DynamicPerlin3DCache<"perlin3dCache__">
instance
(
const root: TgpuRoot
root
,
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
(10, 10, 1));
// A function for updating the size of the cache
function
function initBindGroup(size: d.v3u): TgpuBindGroup<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>
initBindGroup
(
size: d.v3u
size
:
import d
d
.
export v3u

Interface representing its WGSL vector type counterpart: vec3u or vec3. A vector with 3 elements of type u32

v3u
) {
const cache: perlin3d.DynamicPerlin3DCache<"perlin3dCache__">
cache
.
DynamicPerlin3DCache<"perlin3dCache__">.size: d.v3u
size
=
size: d.v3u
size
;
return
const root: TgpuRoot
root
.
TgpuRoot.createBindGroup<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>(layout: TgpuBindGroupLayout<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>, entries: ExtractBindGroupInputFromLayout<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>): TgpuBindGroup<...>

Creates a group of resources that can be bound to a shader based on a specified layout.

@example

const fooLayout = tgpu.bindGroupLayout({ foo: { uniform: d.vec3f }, bar: { texture: 'float' }, });

const fooBuffer = ...; const barTexture = ...;

const fooBindGroup = root.createBindGroup(fooLayout, { foo: fooBuffer, bar: barTexture, });

@paramlayout Layout describing the bind group to be created.

@paramentries A record with values being the resources populating the bind group and keys being their associated names, matching the layout keys.

createBindGroup
(
const dynamicLayout: TgpuBindGroupLayout<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>
dynamicLayout
,
const cache: perlin3d.DynamicPerlin3DCache<"perlin3dCache__">
cache
.
DynamicPerlin3DCache<"perlin3dCache__">.bindings: {
perlin3dCache__size: TgpuBuffer<d.Vec4u> & UniformFlag;
perlin3dCache__memory: TgpuBuffer<d.WgslArray<d.Vec3f>> & StorageFlag;
}
bindings
);
}
let
let bindGroup: TgpuBindGroup<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>
bindGroup
=
function initBindGroup(size: d.v3u): TgpuBindGroup<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>
initBindGroup
(
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
(10, 10, 1));
// Dispatching the pipeline
const pipeline: TgpuComputePipeline
pipeline
.
TgpuComputePipeline.with(bindGroup: TgpuBindGroup): TgpuComputePipeline (+1 overload)
with
(
let bindGroup: TgpuBindGroup<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>
bindGroup
)
.
TgpuComputePipeline.dispatchWorkgroups(x: number, y?: number, z?: number): void
dispatchWorkgroups
(1);
// Can be called again to reinitialize the cache with
// a different domain size
let bindGroup: TgpuBindGroup<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>
bindGroup
=
function initBindGroup(size: d.v3u): TgpuBindGroup<{
perlin3dCache__size: {
uniform: d.Vec4u;
};
perlin3dCache__memory: {
storage: (elementCount: number) => d.WgslArray<d.Vec3f>;
access: "readonly";
};
}>
initBindGroup
(
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
(5, 5, 1));

The package provides convenient way to change PRNG as needed. You can easily implement your own PRNG and plug it into the pipeline.

import {
const randomGeneratorSlot: TgpuSlot<StatefulGenerator>
randomGeneratorSlot
,
type
(alias) interface StatefulGenerator
import StatefulGenerator
StatefulGenerator
,
} from '@typegpu/noise';
const
const LCG: StatefulGenerator
LCG
:
(alias) interface StatefulGenerator
import StatefulGenerator
StatefulGenerator
= (() => {
const
const seed: TgpuVar<"private", d.U32>
seed
=
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
.
privateVar: <d.U32>(dataType: d.U32, initialValue?: number | undefined) => TgpuVar<"private", d.U32>

Defines a variable scoped to each entry function (private).

@paramdataType The schema of the held data's type

@paraminitialValue If not provided, the variable will be initialized to the dataType's "zero-value".

privateVar
(
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 u32To01Float: TgpuFn<(value: d.U32) => d.F32>
u32To01Float
=
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.U32], d.F32>(argTypes: [d.U32], returnType: d.F32) => TgpuFnShell<[d.U32], d.F32> (+2 overloads)
fn
([
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
],
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
)((
value: number
value
) => {
const
const mantissa: number
mantissa
=
value: number
value
>> 9;
const
const bits: number
bits
= 0x3F800000 |
const mantissa: number
mantissa
;
const
const f: number
f
=
import std
std
.
function bitcastU32toF32(value: number): number (+3 overloads)
export bitcastU32toF32
bitcastU32toF32
(
const bits: number
bits
);
return
const f: number
f
- 1;
});
return {
StatefulGenerator.seed2?: (seed: d.v2f) => void
seed2
: (
value: d.v2f
value
:
import d
d
.
export v2f

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

v2f
) => {
'use gpu';
const seed: TgpuVar<"private", d.U32>
seed
.
TgpuVar<"private", U32>.$: number
$
=
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
(
value: d.v2f
value
.
v2f.x: number
x
*
import std
std
.
function pow(base: number, exponent: number): number (+1 overload)
export pow
pow
(32, 3) +
value: d.v2f
value
.
v2f.y: number
y
*
import std
std
.
function pow(base: number, exponent: number): number (+1 overload)
export pow
pow
(32, 2));
},
StatefulGenerator.sample: () => number
sample
: () => {
'use gpu';
const seed: TgpuVar<"private", d.U32>
seed
.
TgpuVar<"private", U32>.$: number
$
=
const seed: TgpuVar<"private", d.U32>
seed
.
TgpuVar<"private", U32>.$: number
$
* 1664525 + 1013904223; // % 2 ^ 32
return
const u32To01Float: (value: number) => number
u32To01Float
(
const seed: TgpuVar<"private", d.U32>
seed
.
TgpuVar<"private", U32>.$: number
$
);
},
};
})();
const
const pipeline: TgpuComputePipeline
pipeline
=
const root: TgpuRoot
root
.
Withable<WithBinding>.with<StatefulGenerator>(slot: TgpuSlot<StatefulGenerator>, value: Eventual<StatefulGenerator>): WithBinding (+2 overloads)
with
(
const randomGeneratorSlot: TgpuSlot<StatefulGenerator>
randomGeneratorSlot
,
const LCG: StatefulGenerator
LCG
)
.
WithBinding.createComputePipeline<{}>(descriptor: TgpuComputePipeline.Descriptor<{}>): TgpuComputePipeline
createComputePipeline
({
compute: TgpuComputeFn<{}>
compute
:
const f: TgpuComputeFn<{}>
f
});